【问题标题】:Java Reading from a File using FileChannelJava 使用 FileChannel 从文件中读取
【发布时间】:2013-03-14 14:50:49
【问题描述】:

在读取大文件时,我从这段代码中得到了一些奇怪的输出,该文件是使用 while 循环打印到 99,999 位的,但是,在读取文件并打印内容时,它只输出 99,988 行。另外,使用 ByteBuffer 是读取文件的唯一选择吗?我见过其他一些使用 CharBuffer 的代码,但我不确定应该使用哪一个,以及在什么情况下应该使用它们。 注意:filePath 是指向磁盘上文件的 Path 对象。

    private void byteChannelTrial() throws Exception {
        try (FileChannel channel = (FileChannel) Files.newByteChannel(filePath, READ)) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            String encoding = System.getProperty("file.encoding");
            while (channel.read(buffer) != -1) {
                buffer.rewind();
                System.out.print(Charset.forName(encoding).decode(buffer));
                buffer.clear();
            }
        }

【问题讨论】:

  • 该代码应正确打印文件的全部内容。它是否打印正确打印的内容?您是否考虑过使用 BufferedReader 包裹 InputStreamReader 包裹 FileInputStream?
  • 你在计算数字还是线(你提到两者)?另外,您如何确定写入的行数?
  • 每个新整数对应一行。所以数字计数就是行数。

标签: java file io nio filechannel


【解决方案1】:

通常,在读取缓冲区数据之前调用flip()。 rewind() 方法执行以下工作:

public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
}

它没有像 flip() 那样设置“限制”:

public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

所以,在阅读之前使用 flip() 而不是 rewind() 取一个托盘。

【讨论】:

    【解决方案2】:

    对于阅读文本,BufferedReader 是最好的

        try (BufferedReader rdr = Files.newBufferedReader(Paths.get("path"),
                Charset.defaultCharset())) {
            for (String line; (line = rdr.readLine()) != null;) {
                System.out.println(line);
            }
        }
    

    顺便说一句

    String encoding = System.getProperty("file.encoding");
    Charset.forName(encoding);
    

    等价于

    Charset.defaultCharset();
    

    【讨论】:

      【解决方案3】:

      嗯,事实证明这种组合是有效的:

          private void byteChannelTrial() throws Exception {
              try (FileChannel channel = (FileChannel) Files.newByteChannel(this.filePath, READ)) {
                  ByteBuffer buffer = ByteBuffer.allocate(1024);
                  while (channel.read(buffer) != -1) {
                      buffer.flip();
                      System.out.print(Charset.defaultCharset().decode(buffer));
                      buffer.clear();
                  }
              }
          }
      

      至于它为什么起作用,我不太确定。

      【讨论】:

      • 这是有效的,因为根据@horaceman 的回答,您调用的是flip() 而不是rewind()。
      • 作为参考,此代码可能无法解码多字节字符,或在缓冲区限制上组合字符(变音符号、表情符号),因为当前缓冲区中的字节可能不完整。这通常发生在 UTF-8 编码中。
      猜你喜欢
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 2010-09-10
      • 2019-04-18
      • 1970-01-01
      • 2011-02-27
      • 2020-09-02
      • 1970-01-01
      相关资源
      最近更新 更多