简体   繁体   中英

Flutter/Dart : reading in text file is prefixed by weird characters

I'm moving from Android Studio to flutter. In the Android Studio project , I write files in a JSON format using this code:

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();
  }

I now want to load in these files in Flutter SDK using this code

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 [];
}

But the problem is that the string jsonstr is now prefixed by weird characters. Here's how it is saved and loaded in at Android Studio

{"property1":"value1", ...}

and this is how it's read in in Flutter SDK

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

I also tried using utf8 encoding but this raises an exception

Failed to decode data using encoding 'utf-8'

So how to get the normal JSON string without the weird symbols before it?

Your title says "reading in text file...", but of course you aren't reading in a text file - you are reading in a Java object serialization, as created by ObjectOutputStream.writeObject() . So now you need to read and interpret that format .

As you've written a single string, the output will consist of the stream header, then a string identifier plus the length of the string, then the string.

Create a method to read the file and parse the header:

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));
} 

and call it from your loop:

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;
}

or like this

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))));
}

Note that there's a bug in your version. You only add members to items in the then which won't get executed until the future. It's simpler to get right with the await syntax.

您还需要在Java代码中使用utf8编码写入文件:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM