flutter 使用archive压缩与解压文件时出现中文乱码的问题

archive 是 flutter 上的一个文件压缩与解压的类库,支持 zip,tar,zlip,gzip,zip2,xz 格式的压缩与解压。

archive 的使用

archive 主要通过 Archive,ArchiveFile,ZipEncoder,ZipDecoder 三个类来实现文件的压缩和解压。

ArchiveFile 表示压缩包内的一个文件。

Archive 表示一个压缩包。

ZipEncoder 表示 zip 编码器。

ZipDecoder 表示 zip 解码器。

文件压缩:

dart 复制代码
final zipFile = File("text.zip");   
final archive = Archive();  
var str="中文";
final archiveFile=ArchiveFile.string("test.txt", str); //将压缩内容添加到ArchiveFile
archive.addFile(archiveFile);  //将ArchiveFile添加到Archive
final zipData = ZipEncoder().encode(archive);  //使用zip编码
zipFile.writeAsBytesSync(zipData!);  //写入到压缩文件

文件解压:

dart 复制代码
final zipFile = File("text.zip");
var archive=ZipDecoder().decodeBytes(zipFile.readAsBytesSync()); //读取文件内容,使用ZipDecoder解码
ArchiveFile? f=archive.findFile("test.txt");  //从压缩包内寻找文件
var content=f?.content;  //获取内容

乱码分析

对于非中文内容来说,直接使用以上代码来实现压缩和解压是不会导致乱码,但是对于中文来说却会导致乱码。

首先来分析 ArchiveFile.string() 方法做了什么。

dart 复制代码
ArchiveFile.string(this.name, String content,  
    [this._compressionType = STORE]) {  
  size = content.length;  
  _content = Uint8List.fromList(content.codeUnits);  
  _rawContent = InputStream(_content);  
}

能看到,该方法首先获取传入字符串的 utf-16 编码的列表,再将其转为 uint8 列表。uint8 在 flutter 中表示 8 位比特(bit)的无符号数,范围为 [0,256)。因为文件就是按字节(Byte)存储的,一个字节由 8 位比特组成,范围跟 uint8 一致。

但是对于中文来说,大小是超过 256 的,所以当使用 Uint8List.fromList() 将中文从 utf-16 强转为 uint8,会导致其被截断,从而导致乱码。

从下面测试例子中也能看出来:

dart 复制代码
String str="中文";  
var list=str.codeUnits;  
print(list);  
var list2=Uint8List.fromList(list);  
print(list2);

//运行结果为:
[20013, 25991]
[45, 135]

所以对于中文来说,并不能直接强制为 uint8,需要对其进行编码再进行存储,中文编码方式存在 utf-8,gbk 等,而 flutter 支持 utf-8 编码,但不支持 gbk 编码。对于 utf-8 编码来说,中文需要 3 个字节来存储。

dart 复制代码
utf8.encode(); //编码
utf8.decode(); //解码

我们再来看,ArchiveFile 的构造方法除了 ArchiveFile.string() 外,还有

dart 复制代码
ArchiveFile(this.name, this.size, dynamic content,  
    [this._compressionType = STORE]) {  
  name = name.replaceAll('\\', '/');  
  if (content is Uint8List) {  
    _content = content;  
    _rawContent = InputStream(_content);  
    if (size <= 0) {  
      size = content.length;  
    }  
  } else if (content is InputStream) {  
    _rawContent = InputStream.from(content);  
    if (size <= 0) {  
      size = content.length;  
    }  
  } else if (content is InputStreamBase) {  
    _rawContent = content;  
    if (size <= 0) {  
      size = content.length;  
    }  
  } else if (content is TypedData) {  
    _content = Uint8List.view(content.buffer);  
    _rawContent = InputStream(_content);  
    if (size <= 0) {  
      size = (_content as Uint8List).length;  
    }  
  } else if (content is String) {  
    _content = content.codeUnits;  
    _rawContent = InputStream(_content);  
    if (size <= 0) {  
      size = content.codeUnits.length + 1;  
    }  
  } else if (content is List<int>) {  
    // Legacy  
    // This expects the list to be a list of bytes, with values [0, 255].  
    _content = content;  
    _rawContent = InputStream(_content);  
    if (size <= 0) {  
      size = content.length;  
    }  
  } else if (content is FileContent) {  
    _content = content;  
  }  
}

当传入的 content 类型为 List<int> 时,直接赋值为 _content,没有进行额外的操作。另外该方法还有另外一个参数 _compressionType,该参数需要传入 ArchiveFile.STORE,否则在进行解压时,archiveFile.content 会报错:Unhandled Exception: RangeError: Value not in range: -6128

解决办法

所以最后处理中文乱码的解决办法就是先对其进行 utf-8 编码,再压缩。解压后,对其进行 utf-8 解码,获取中文内容。

代码如下:

dart 复制代码
//压缩
final zipFile = File("text.zip");  
final archive = Archive();  
var str="中文";
//这步是必须的
var encodeStr=utf8.encode(str);   
//必须要为ArchiveFile.STORE
final archiveFile=ArchiveFile("test.txt",str.length,encodeStr,ArchiveFile.STORE); 
archive.addFile(archiveFile);  
final zipData =  ZipEncoder().encode(archive);  
zipFile.writeAsBytesSync(zipData!);  

//解压
ArchiveFile? 
f=ZipDecoder().decodeBytes(zipFile.readAsBytesSync()).findFile("test.txt");  
var content=f?.content;  
// 解码
print(utf8.decode(content));
相关推荐
勤劳打代码27 分钟前
追本溯源 —— SetState 刷新做了什么
flutter·面试·性能优化
松☆2 小时前
OpenHarmony 后台任务与 Flutter 生命周期协调:构建稳定可靠的混合应用
flutter
松☆2 小时前
Flutter 与 OpenHarmony 深度集成:自定义 MethodChannel 插件开发全指南
flutter·wpf
克喵的水银蛇2 小时前
Flutter 布局实战:掌握 Row/Column/Flex 弹性布局
前端·javascript·flutter
sunly_3 小时前
Flutter:实现多图上传选择的UI
flutter·ui
倔强_build3 小时前
flutter app 状态栏
flutter
晚霞的不甘4 小时前
深度解析:Flutter 与 OpenHarmony 融合架构下的跨平台渲染机制与系统级集成
flutter·架构
kirk_wang4 小时前
Flutter图片库CachedNetworkImage鸿蒙适配:从原理到实践
flutter·移动开发·跨平台·arkts·鸿蒙
松☆4 小时前
Flutter 与 OpenHarmony 数据持久化协同方案:从 Shared Preferences 到分布式数据管理
分布式·flutter
松☆4 小时前
OpenHarmony + Flutter 离线能力构建指南:打造无网可用的高可靠政务/工业应用
flutter·政务