如何使用 AsynchronousFileChannel 有效地读取到 StringBuffer
How to use AsynchronousFileChannel to read to a StringBuffer efficiently
所以你知道你可以使用 AsynchronousFileChannel 将整个文件读取到一个字符串中:
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(filePath, StandardOpenOption.READ);
long len = fileChannel.size();
ReadAttachment readAttachment = new ReadAttachment();
readAttachment.byteBuffer = ByteBuffer.allocate((int) len);
readAttachment.asynchronousChannel = fileChannel;
CompletionHandler<Integer, ReadAttachment> completionHandler = new CompletionHandler<Integer, ReadAttachment>() {
@Override
public void completed(Integer result, ReadAttachment attachment) {
String content = new String(attachment.byteBuffer.array());
try {
attachment.asynchronousChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
completeCallback.accept(content);
}
@Override
public void failed(Throwable exc, ReadAttachment attachment) {
exc.printStackTrace();
exceptionError(errorCallback, completeCallback, String.format("error while reading file [%s]: %s", path, exc.getMessage()));
}
};
fileChannel.read(
readAttachment.byteBuffer,
0,
readAttachment,
completionHandler);
假设现在,我不想分配整个ByteBuffer
,而是逐行读取。我可以使用固定宽度的 ByteBuffer
并多次调用 read
,总是复制并附加到 StringBuffer 直到我没有换行......我唯一关心的是:因为我正在读取的文件的编码可能是每个字符多字节(UTF 之类的),读取的字节可能以不完整的字符结尾。我如何确保将正确的字节转换为字符串而不是弄乱编码?
更新:答案在所选答案的评论中,但它基本上指向CharsetDecoder。
如果您有明确的 ASCII 分隔符(\n),您就不需要关心不完整的字符串,因为这个字符映射到单字节(反之亦然)。
因此只需在您的输入中搜索“\n”字节,然后读取之前的任何内容并将其转换为字符串。循环直到找不到更多新行。然后压缩缓冲区并将其重新用于下一次读取。如果找不到新行,则必须分配更大的缓冲区,复制旧行的内容,然后再次调用读取。
编辑:如评论中所述,您可以即时将 ByteBuffer 传递给 CharsetDecoder 并将其转换为 CharBuffer(然后附加到 StringBuilder 或任何首选解决方案)。
试用扫描仪:
Scanner sc = new Scanner(FileChannel.open(filePath, StandardOpenOption.READ));
String line = sc.readLine();
FileChannel 是 InterruptibleChannel
所以你知道你可以使用 AsynchronousFileChannel 将整个文件读取到一个字符串中:
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(filePath, StandardOpenOption.READ);
long len = fileChannel.size();
ReadAttachment readAttachment = new ReadAttachment();
readAttachment.byteBuffer = ByteBuffer.allocate((int) len);
readAttachment.asynchronousChannel = fileChannel;
CompletionHandler<Integer, ReadAttachment> completionHandler = new CompletionHandler<Integer, ReadAttachment>() {
@Override
public void completed(Integer result, ReadAttachment attachment) {
String content = new String(attachment.byteBuffer.array());
try {
attachment.asynchronousChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
completeCallback.accept(content);
}
@Override
public void failed(Throwable exc, ReadAttachment attachment) {
exc.printStackTrace();
exceptionError(errorCallback, completeCallback, String.format("error while reading file [%s]: %s", path, exc.getMessage()));
}
};
fileChannel.read(
readAttachment.byteBuffer,
0,
readAttachment,
completionHandler);
假设现在,我不想分配整个ByteBuffer
,而是逐行读取。我可以使用固定宽度的 ByteBuffer
并多次调用 read
,总是复制并附加到 StringBuffer 直到我没有换行......我唯一关心的是:因为我正在读取的文件的编码可能是每个字符多字节(UTF 之类的),读取的字节可能以不完整的字符结尾。我如何确保将正确的字节转换为字符串而不是弄乱编码?
更新:答案在所选答案的评论中,但它基本上指向CharsetDecoder。
如果您有明确的 ASCII 分隔符(\n),您就不需要关心不完整的字符串,因为这个字符映射到单字节(反之亦然)。
因此只需在您的输入中搜索“\n”字节,然后读取之前的任何内容并将其转换为字符串。循环直到找不到更多新行。然后压缩缓冲区并将其重新用于下一次读取。如果找不到新行,则必须分配更大的缓冲区,复制旧行的内容,然后再次调用读取。
编辑:如评论中所述,您可以即时将 ByteBuffer 传递给 CharsetDecoder 并将其转换为 CharBuffer(然后附加到 StringBuilder 或任何首选解决方案)。
试用扫描仪:
Scanner sc = new Scanner(FileChannel.open(filePath, StandardOpenOption.READ));
String line = sc.readLine();
FileChannel 是 InterruptibleChannel