【问题标题】:How to use AsynchronousFileChannel to read to a StringBuffer efficiently如何使用 AsynchronousFileChannel 有效地读取 StringBuffer
【发布时间】:2016-01-16 20:04:17
【问题描述】:

所以你知道你可以使用 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

【问题讨论】:

  • 不要使用异步 I/O 读取行。只是不合适。 BufferedReader.readLine(). 每秒可以读取数百万行
  • 我需要非阻塞操作!
  • 那你为什么要使用异步 I/O?这不是非阻塞的。它是继阻塞和非阻塞之后的第三种范式。但是为什么你认为你不能首先使用阻塞 I/O?
  • 如果我使用 Handler 它应该是非阻塞的,不是吗?您还建议什么其他范式?

标签: java nio utf


【解决方案1】:

如果您有明确的 ASCII 分隔符(\n),则无需关心不完整的字符串,因为此字符映射到单字节(反之亦然)。

所以只需在输入中搜索“\n”字节,然后读取之前的任何内容并将其转换为字符串。循环直到找不到更多新行。然后压缩缓冲区并将其重用于下一次读取。如果找不到新行,则必须分配更大的缓冲区,复制旧缓冲区的内容,然后再次调用读取。

编辑:如评论中所述,您可以将 ByteBuffer 即时传递给 CharsetDecoder 并将其转换为 CharBuffer(然后附加到 StringBuilder 或任何首选的解决方案)。

【讨论】:

  • 无论如何我都必须将整行存储为字节缓冲区...让我们暂时忘记我正在处理行...而且我的缓冲区是有限的(行可以很长)。我们会怎么做?
  • 您可以使用docs.oracle.com/javase/7/docs/api/java/nio/charset/… 即时转换输入。您仍然需要管理缓冲区,因为它可能包含读取之间的剩余字符。
  • 完美!谢谢,考虑更新答案
【解决方案2】:

试用扫描仪:

    Scanner sc = new Scanner(FileChannel.open(filePath, StandardOpenOption.READ));
   String line = sc.readLine();

FileChannel 是 InterruptibleChannel

【讨论】:

  • 再说一次,我不需要可中断性,我需要稍后开始读取和回调...
猜你喜欢
  • 2017-04-27
  • 1970-01-01
  • 2021-06-12
  • 2018-05-23
  • 1970-01-01
  • 1970-01-01
  • 2016-08-22
  • 2013-07-15
  • 2015-07-16
相关资源
最近更新 更多