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));
相关推荐
Gorit1 小时前
如何使用 Flutter 开发 HarmonyOS 应用
flutter·华为·harmonyos
孤影过客1 小时前
Flutter高性能任务管理APP开发实战代码解析
jvm·flutter·oracle
键盘鼓手苏苏14 小时前
Flutter 三方库 p2plib 的鸿蒙化适配指南 - 实现高性能的端到端(P2P)加密通讯、支持分布式节点发现与去中心化数据流传输实战
flutter·harmonyos·鸿蒙·openharmony
加农炮手Jinx14 小时前
Flutter for OpenHarmony:postgrest 直接访问 PostgreSQL 数据库的 RESTful 客户端(Supabase 核心驱动) 深度解析与鸿蒙适配指南
数据库·flutter·华为·postgresql·restful·harmonyos·鸿蒙
加农炮手Jinx14 小时前
Flutter 组件 heart 适配鸿蒙 HarmonyOS 实战:分布式心跳监控,构建全场景保活检测与链路哨兵架构
flutter·harmonyos·鸿蒙·openharmony
钛态14 小时前
Flutter 三方库 http_mock_adapter — 赋能鸿蒙应用开发的高效率网络接口 Mock 与自动化测试注入引擎(适配鸿蒙 HarmonyOS Next ohos)
android·网络协议·flutter·http·华为·中间件·harmonyos
王码码203514 小时前
Flutter for OpenHarmony:Flutter 三方库 algoliasearch 毫秒级云端搜索体验(云原生搜索引擎)
android·前端·git·flutter·搜索引擎·云原生·harmonyos
王码码203514 小时前
Flutter 三方库 dns_client 的鸿蒙化适配指南 - 告别 DNS 劫持、探索 DNS-over-HTTPS (DoH) 技术、构建安全的鸿蒙网络请求环境
flutter·harmonyos·鸿蒙·openharmony·dns_client
键盘鼓手苏苏14 小时前
Flutter 组件 highlighter 适配鸿蒙 HarmonyOS 实战:高性能语法高亮,构建大规模代码分析与文本染色架构
flutter·harmonyos·鸿蒙·openharmony
国医中兴14 小时前
Flutter 三方库 langchain_google 的鸿蒙化适配指南 - 链接 Gemini 智慧中枢、LangChain AI 实战、鸿蒙级智能应用专家
flutter·langchain·harmonyos