Dart 原生SDK預設支援UTF-8編碼,無論是File 還是HttpClient介面,預設提供的encoding 都是utf-8。
例如,file.dart 中,openWrite方法預設encoding就是utf8,這樣生成的檔案預設就是utf-8編碼的。
//file.dart
IOSink openWrite({FileMode mode: FileMode.write, Encoding encoding: utf8});
複製程式碼
本文提供了一個gbk codec, 相容原生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: ^0.1.1
- 更新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:
gbk2utf8 的效率略高,同樣介面耗費240ms, 跟蹤發現gbk解碼時先轉為unicode, 然後unicode轉為utf8, utf8再轉為String。
實際上,Dart String就是按照UTF-16編碼實現的,支援unicode。gbk2utf8實際上浪費了一半的解碼時間,因此效率不高。
fast_gbk 測試結果如下,同樣介面耗時150ms,是三個codec中解碼最快速的,介面明顯不再卡頓。
由於fast_gbk支援Stream介面,在大量資料編解碼時比直接encode,decode效率會更高些,使用也更方便。
-
Q:穩定麼?有沒有bug?
-
A:目前測試用例已經覆蓋了所有utf-8字元和GBK字元,如果發現有bug,程式碼已經在Github上開源,歡迎提交 issue 和 pull request。pub連結為: pub.dev