Java nio:如何使用正确的字符集从内存映射文件中读取字符

4

针对一个新项目,我需要读取文件的字符(并且可以配置编码方式)以处理输入。由于某些文件可能会相当大(>100MB),因此我想尝试使用Java NIO内存映射文件进行更快速的访问。

但是,我无法确定该如何创建类似于“Reader”的内容,以从MappedByteBuffer中读取正确的字符集解码。

目前,我使用以下代码来创建MappedByteBuffer:

    RandomAccessFile raFile = new RandomAccessFile("myFile.bla", "r");
    FileChannel channel = raFile.getChannel();
    MappedByteBuffer mappedByteBuffer = channel.map(MapMode.READ_ONLY, 0, channel.size());

我知道可以使用getChar()方法从MappedByteBuffer中获取字符,但如何指定编码呢?在javadoc中说明,始终会读取两个字节并组合成一个字符,但对于ASCII编码的文件呢?
我还发现了Channels.newReader(...)方法,但它只能处理通道,而不能处理内存映射文件。是否有类似于MappedByteBuffer的方法呢?
只是为了确保:我知道内存映射是一种比较昂贵的操作,因此仅适用于较大的文件。我还没有决定是否要使用它,但想为我的特殊用例评估一下。
非常感谢您的帮助,谢谢!

2
为什么不获取底层字节并使用适当的Charset构造一个String - Sotirios Delimanolis
1
内存映射对于小文件来说也不是很昂贵。它只需要大约30微秒的时间,速度并不慢。 - Peter Lawrey
@SotiriosDelimanolis 构建字符串并不高效,因为我需要单个字符并根据它们分析上下文。之后,一些字符可能会组合成一个字符串。(类似于对源代码文件进行词法分析)。 - andy
1个回答

5
你可以使用从你喜欢的Charset检索到的CharsetDecoder,并使用Charset#newDecoder()
StandardCharsets.UTF_8.newDecoder().decode(mappedByteBuffer)

这会返回一个CharBuffer,您可以从中获取char
请注意,这将消耗整个MappedByteBuffer。如果您只想要几个字节,请从原始的MappedByteBuffer的几个字节构造一个新的ByteBuffer并对其进行解码。

1
+1 你可以使用slice()方法从一个较大的ByteBuffer中选择一些字节。 - Peter Lawrey
我实际上想要消耗所有数据,但是我需要逐个字符地进行。一次性解码不是选项,因为它需要双倍的内存,而即时解码则不需要额外的空间。我实际上正在寻找一种像Reader使用FileInputStream一样即时解码内存映射文件的方法。 - andy
@andy 内存映射文件已经在Java内存中了。可以根据需要从其中提取字节。 - Sotirios Delimanolis
我知道这一点,问题是:我想读取以特定字符集(可能因文件而异)解码的字符。因此,我希望找到类似于Reader的东西,可以为我处理所有解码工作,但是可以在内存映射文件上工作。 - andy
@andy 没有从 ByteBuffer 读取的 ReaderInputStream 类型。您可以自己实现。如我的答案(和Peter的评论)中所讨论的,每次取2个字节,将它们包装在 ByteBuffer 中,并将其解码为 CharBuffer,从中获取 char - Sotirios Delimanolis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接