Java字符集InputStreamReader,文件通道差异



我正在尝试读取一个编码为UTF-16文件的(日语)文件。

当我使用字符集为"UTF-16"的InputStreamReader读取它时,文件读取正确:

try {
InputStreamReader read = new InputStreamReader(new FileInputStream("JapanTest.txt"), "UTF-16");
BufferedReader in = new BufferedReader(read);
String str;
while((str=in.readLine())!=null){           
System.out.println(str);
}
in.close();
}catch (Exception e){
System.out.println(e);
}

然而,当我使用文件通道并从字节数组中读取时,字符串并不总是正确转换:

File f = new File("JapanTest.txt");
fis = new FileInputStream(f);
channel = fis.getChannel();
MappedByteBuffer buffer = channel.map( FileChannel.MapMode.READ_ONLY, 0L, channel.size());
buffer.position(0);
int get = Math.min(buffer.remaining(), 1024);
byte[] barray = new byte[1024];
buffer.get(barray, 0, get);
CharSet charSet = Charset.forName("UTF-16");
//endOfLinePos is a calculated value and defines the number of bytes to read
rowString = new String(barray, 0, endOfLinePos, charSet);               
System.out.println(rowString);

我发现的问题是,只有当MappedByteBuffer位于0位置时,我才能正确读取字符。如果我增加MappedByteBuffer的位置,然后将一些字节读取到字节数组中,然后使用字符集UTF-16将其转换为字符串,那么这些字节没有正确转换。如果文件是用UTF-8编码的,我还没有遇到过这个问题,那么这只是UTF-16的问题吗?

更多详细信息:我需要能够从文件通道读取任何一行,因此为此,我构建了一个行结束字节位置列表,然后使用这些位置能够获得任何给定行的字节,然后将它们转换为字符串。

UTF-16的代码单元是2个字节,而不是像UTF-8那样的字节。模式和单字节代码单元长度使UTF-8自同步;它可以在任何时候正确读取,如果它是一个连续字节,它可以回溯或只丢失一个字符。

使用UTF-16时,必须始终使用成对的字节,不能从奇数字节开始读取或从奇数字节停止读取。您还必须知道endianes,并且在不读取文件开头时使用UTF-16LE或UTF-16BE,因为不会有BOM。

您也可以将文件编码为UTF-8。

InputStreamReader可能会进行一些转换,而普通new String(...)则不会。作为一种变通方法(并验证这一假设),您可以尝试像new InputStreamReader( new ByteArrayInputStream( barray ) )一样包装从通道读取的数据。

编辑:忘记这一点:)-Channels.newReader()将是一条路。

最新更新