Flutter/Dart:读取文本文件以奇怪的字符为前缀

Posted

技术标签:

【中文标题】Flutter/Dart:读取文本文件以奇怪的字符为前缀【英文标题】:Flutter/Dart : reading in text file is prefixed by weird characters 【发布时间】:2020-01-19 12:38:36 【问题描述】:

我正在从 android Studio 迁移到 Flutter。在 Android Studio 项目中,我使用以下代码以 JSON 格式编写文件:

String json = gson.toJson(item);
FileOutputStream fos = null;
try 
  fos = context.openFileOutput("item"+ item.getUid(), Context.MODE_PRIVATE);
  ObjectOutputStream os = new ObjectOutputStream(fos);
  os.writeObject(json);
  os.close();
  fos.close();
   catch (FileNotFoundException e) 
      e.printStackTrace();
   catch (IOException e) 
      e.printStackTrace();
  

我现在想使用此代码在 Flutter SDK 中加载这些文件

Future<List<Item>> loadAllItems() async 
  try
    var items = <Item>[];
    var filesDir = Directory("/data/user/0/com.company.app/files");

    for(var f in filesDir.listSync())
      if(f is File)
        f.readAsString(encoding: latin1).then((jsonstr) => 
          items.add(parse(jsonstr))
        );
      
    
    return items;
   catch(e)
    log(e);
  
  return [];

但问题是字符串jsonstr 现在以奇怪的字符为前缀。 这是它在 Android Studio 中的保存和加载方式

"property1":"value1", ...

这就是它在 Flutter SDK 中的读取方式

’ t$"property1":"value1", ...

我也尝试过使用 utf8 编码,但这会引发异常

使用编码“utf-8”解码数据失败

那么如何获取前面没有奇怪符号的普通 JSON 字符串呢?

【问题讨论】:

这三个字符不是告诉ObjectInputStream后面字节的java类型的前缀吗?它们看起来像来自docs.oracle.com/javase/8/docs/platform/serialization/spec/… 的流魔术字节。您需要将它们剪掉(它们应该始终相同 - 考虑到 2 个字节对字符串长度进行编码),然后 UTF-8 解码其余部分。 【参考方案1】:

您的标题是“正在读取文本文件...”,但您当然不是在读取 text 文件 - 您正在读取由 @987654322 创建的 Java 对象序列化@。所以现在你需要阅读和解释that format。

当您编写单个字符串时,输出将包含流标头,然后是 string 标识符加上字符串的长度,然后是字符串。

创建一个读取文件并解析头部的方法:

Future<String> readJavaObjectFile(File file) async 
  var bytes = await file.readAsBytes() as Uint8List;
  var data = bytes.buffer.asByteData();
  assert(data.getUint16(0) == 0xaced); // stream_magic
  assert(data.getUint16(2) == 5); // stream_version
  assert(bytes[4] == 0x74); // tc_string
  var length = data.getUint16(5); // length thereof
  return utf8.decode(bytes.sublist(7, 7 + length));
 

并从您的循环中调用它:

Future<List<Item>> loadAllItems(Directory filesDir) async 
  var items = <Item>[];
  for (var f in await filesDir.list().where((e) => e is File).toList()) 
    items.add(parse(await readJavaObjectFile(f)));
  
  return items;

或者像这样

Future<List<Item>> loadAllItems(Directory filesDir) async 
  var files = await filesDir.list().where((e) => e is File).toList();
  return await Future.wait(
      files.map<Future<Item>>((f) async => parse(await readJavaObjectFile(f))));

请注意,您的版本中存在错误。您只需将成员添加到then 中的items,直到将来才会执行。使用await 语法更简单。

【讨论】:

【参考方案2】:

您还需要在您的 java 代码中写入带有 utf8 编码的文件:

ObjectOutputStream os = new ObjectOutputStream(fos, StandardCharsets.UTF_8));

【讨论】:

那么默认编码是什么?而且由于这已经太晚了(应用程序已经部署到成千上万的用户并且需要保留他们的数据),有什么办法可以解决这个问题? 我快速搜索了一下,发现了这个:***.com/questions/4390457/…@WouterVandenpette

以上是关于Flutter/Dart:读取文本文件以奇怪的字符为前缀的主要内容,如果未能解决你的问题,请参考以下文章

为啥以文本形式打开图像文件会打印出奇怪的字符?

Flutter/Dart - 文本值未正确显示

如何在视频/图像上添加图像或文本(水印) - Flutter/Dart

将文本写入文件后的mfc c++奇怪的块字符

从字符串中删除邮政编码 (Flutter/Dart)

Flutter/Dart json 用特殊字符编码密码