Dart 原生SDK不支持GBK编码,默认支持UTF-8编码,无论是File 还是HttpClient接口,默认提供的encoding 都是utf-8。这样在对接老版本的web接口时很容易产生乱码问题。
例如,file.dart 中,openWrite方法默认encoding就是utf8,这样生成的文件默认就是utf-8编码的。
//file.dart
IOSink openWrite({FileMode mode: FileMode.write, Encoding encoding: utf8});
本文提供了一个gbk codec, 提供GBK和Unicode之间的转换,兼容原生API的stream接口,读写文件和Http的 Stream API更为方便。
例如,使用stream api 生成一个gbk文件流程如下:
import 'dart:io';
import 'package:fast_gbk/fast_gbk.dart';
void main() async {
File output = File("gbk.txt");
var stream = output.openWrite(encoding: gbk);
stream.write("123");
stream.writeln("456");
stream.writeCharCode(0x41);
await stream.close();
}
使用方法
- 添加依赖
pubspec.yaml 中添加依赖
dependencies: fast_gbk: ^1.0.0-rc(原文章的版本过低 这里是最新的版本 支持非空安全)
- 更新pubcache
flutter pub get
- dart文件中添加引用
import 'package:fast_gbk/fast_gbk.dart';
Demo
- 最简单的使用场景,直接编码解码String:
import 'package:fast_gbk/fast_gbk.dart';
void main() async {
var encoded = gbk.encode("白日依山尽,黄河入海流");
var decoded = gbk.decode([176, 215, 200, 213, 210, 192, 201, 189, 190, 161, 163,
172, 187, 198, 186, 211, 200, 235, 186, 163, 193, 247]);
}
- 读GBK编码的文件
import 'dart:convert';
import 'dart:io';
import 'package:fast_gbk/fast_gbk.dart';
void main() {
File gbkFile = File("gbkFile.txt");
var stream = gbkFile.openRead();
stream.transform(gbk.decoder)
.transform(const LineSplitter())
.listen((line) {
stdout.writeln(line);
});
}
- 写GBK编码的文件
import 'dart:io';
import 'package:fast_gbk/fast_gbk.dart';
void main() async {
File output = File("gbk.txt");
var stream = output.openWrite(encoding: gbk);
stream.write("123");
stream.writeln("456");
stream.writeCharCode(0x41);
await stream.close();
}
- 解码GBK的 HttpClient response
import 'dart:io';
import 'package:fast_gbk/fast_gbk.dart';
void main() async {
var gbkWebUrl = "http://www.newsmth.net/nForum/#!mainpage";
var httpClient = HttpClient();
HttpClientRequest request = await httpClient.getUrl(Uri.parse(gbkWebUrl));
HttpClientResponse response = await request.close();
var responseBody = await response.transform(gbk.decoder).join();
print(responseBody);
httpClient.close();
}
- DIO 中使用 Gbk Codec 解码 response:
options 设定responseDecoder
BaseOptions options = BaseOptions();
options.responseDecoder = gbkDecoder;
_client = Dio(options);
定义gbk Decoder
String gbkDecoder (List<int> responseBytes, RequestOptions options,
ResponseBody responseBody) {
String result = gbk.decode(responseBytes);
return result;
}
Q&A
- Q:又造了一个轮子?和现有的gbk codec有什么区别?
- A:在功能方面,现有的gbk_codec和gbk2utf8都可以支持encode和decode接口,但不支持Stream接口。
例如:response.transform(gbk.decoder), gbk_codec和gbk2utf8不能这样使用。
在效率方面,本文作者在使用 gbk_codec 和 gbk2utf8 解析HttpResponse时都产生了卡顿,因此才重写了这个模块:
gbk_codec 在解码时大量使用了 String+= 拼接字符,使得界面刷新产生了卡顿,如下火焰图显示刷新界面主页时解码耗时了3.8s:
fast_gbk 测试结果如下,同样界面耗时150ms,是三个codec中解码最快速的,界面明显不再卡顿。
由于fast_gbk支持Stream接口,在大量数据编解码时比直接encode,decode效率会更高些,使用也更方便。
- Q:稳定么?有没有bug?
- A:目前测试用例已经覆盖了所有utf-8字符和GBK字符,如果发现有bug,代码已经在Github上开源,欢迎提交 issue 和 pull request。pub链接为: pub.dev