我应该开发一个子系统来存储某个文件中的某些业务数据,但我遇到了一个问题,但我首先要求的是:
我以为我只是将所有内容都放在一个字符串中,用UTF8(一种不会很快消失的格式)对其进行编码并将其写入文件。 问题是,UTF8不允许某些字节组合,并在我稍后再次读取文件时更改它们。
以下是显示问题的示例代码:
// The charset we use to encode the strings / file
Charset charSet = StandardCharsets.UTF_8;
// The byte data we want to store (as ints here because in the app it is used as ints)
int idsToStore[] = new int[] {360, 361, 390, 391};
// We transform our ints to bytes
byte[] bytesToStore = new byte[idsToStore.length * 4];
for (int i = 0; i < idsToStore.length; i++) {
int id = idsToStore[i];
bytesToStore[i * 4 + 0] = (byte) ((id >> 24) & 0xFF);
bytesToStore[i * 4 + 1] = (byte) ((id >> 16) & 0xFF);
bytesToStore[i * 4 + 2] = (byte) ((id >> 8) & 0xFF);
bytesToStore[i * 4 + 3] = (byte) (id & 0xFF);
}
// We transform our bytes to a String
String stringToStore = new String(bytesToStore, charSet);
System.out.println("idsToStore="+Arrays.toString(idsToStore));
System.out.println("BytesToStore="+Arrays.toString(bytesToStore));
System.out.println("StringToStore="+stringToStore);
System.out.println();
// We load our bytes from the "file" (in this case a String, but its the same result)
byte[] bytesLoaded = stringToStore.getBytes(charSet);
// Just to check we see if the resulting String is identical
String stringLoaded = new String(bytesLoaded, charSet);
// We transform our bytes back to ints
int[] idsLoaded = new int[bytesLoaded.length / 4];
int readPos = 0;
for (int i = 0; i < idsLoaded.length; i++) {
byte b1 = bytesLoaded[readPos++];
byte b2 = bytesLoaded[readPos++];
byte b3 = bytesLoaded[readPos++];
byte b4 = bytesLoaded[readPos++];
idsLoaded[i] = (b4 & 0xFF) | (b3 & 0xFF) << 8 | (b2 & 0xFF) << 16 | (b1 & 0xFF) << 24;
}
System.out.println("BytesLoaded="+Arrays.toString(bytesLoaded));
System.out.println("StringLoaded="+stringLoaded);
System.out.println("idsLoaded="+Arrays.toString(idsLoaded));
System.out.println();
// We check everything
System.out.println("Bytes equal: "+Arrays.equals(bytesToStore, bytesLoaded));
System.out.println("Strings equal: "+stringToStore.equals(stringLoaded));
System.out.println("IDs equal: "+Arrays.equals(idsToStore, idsLoaded));
UTF8的输出是:
idsToStore=[360, 361, 390, 391]
BytesToStore=[0, 0, 1, 104, 0, 0, 1, 105, 0, 0, 1, -122, 0, 0, 1, -121]
StringToStore=(can not be pasted into SO)
idsLoaded=[360, 361, 495, -1078132736, 32489405]
BytesLoaded=[0, 0, 1, 104, 0, 0, 1, 105, 0, 0, 1, -17, -65, -67, 0, 0, 1, -17, -65, -67]
StringLoaded=(can not be pasted into SO)
Bytes equal: false
Strings equal: true
IDs equal: false
如果我将Charset更改为UTF16BE(&lt; - BE是Big Endian),则此测试有效! 问题是,我不确定UTF16BE是否适合“偶然”进行此测试。我需要知道它是否会一直有效。或许还有更好的方法。
我很感谢任何建议。提前谢谢。
答案 0 :(得分:2)
确保字符集始终有效的唯一方法是使用整个ASCII表对其进行测试:编写包含所有256个可能值的字节数组,并测试它是否正确读取。
但是,回到问题的根源,我怀疑将所有数据编码成字符串会很好。 String是一种Unicode结构,面向包含可读文本(即它可能不包含32个ascii代码下的某些字符)。
相反,我会想到一个BINARY结构化文件:作为二进制文件,您可以确保它可以透明地包含任何内容。在构建时,您可以确保可以在其上存储多种数据。例如,如果您可以设计由 segment 组成的结构,并且每个段具有其数据长度的标题,那就没关系。二进制段将通过InputStream读取,文本段通过Reader(具有所需的编码)。