archive 是 flutter 上的一个文件压缩与解压的类库,支持 zip,tar,zlip,gzip,zip2,xz 格式的压缩与解压。
archive 的使用
archive 主要通过 Archive,ArchiveFile,ZipEncoder,ZipDecoder 三个类来实现文件的压缩和解压。
ArchiveFile 表示压缩包内的一个文件。
Archive 表示一个压缩包。
ZipEncoder 表示 zip 编码器。
ZipDecoder 表示 zip 解码器。
文件压缩:
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!); //写入到压缩文件
文件解压:
final zipFile = File("text.zip");
var archive=ZipDecoder().decodeBytes(zipFile.readAsBytesSync()); //读取文件内容,使用ZipDecoder解码
ArchiveFile? f=archive.findFile("test.txt"); //从压缩包内寻找文件
var content=f?.content; //获取内容
乱码分析
对于非中文内容来说,直接使用以上代码来实现压缩和解压是不会导致乱码,但是对于中文来说却会导致乱码。
首先来分析 ArchiveFile.string()
方法做了什么。
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,会导致其被截断,从而导致乱码。
从下面测试例子中也能看出来:
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 个字节来存储。
utf8.encode(); //编码
utf8.decode(); //解码
我们再来看,ArchiveFile
的构造方法除了 ArchiveFile.string()
外,还有
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
文章来源:https://www.toymoban.com/news/detail-598479.html
解决办法
所以最后处理中文乱码的解决办法就是先对其进行 utf-8 编码,再压缩。解压后,对其进行 utf-8 解码,获取中文内容。
代码如下:文章来源地址https://www.toymoban.com/news/detail-598479.html
//压缩
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));
到了这里,关于flutter 使用archive压缩与解压文件时出现中文乱码的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!