AsynchronousFileChannel如何读取大文件? Path file=Path.get(“c:/large.log”); AsynchronousFileChannel=AsynchronousFileChannel.open(文件); 最终ByteBuffer缓冲区=ByteBuffer.allocate(1000); 通道读取(缓冲区,0,缓冲区, 新的CompletionHandler(){ 已完成公共作废(整数结果,ByteBuffer附件){ System.out.println(新字符串(buffer.array()); } });

AsynchronousFileChannel如何读取大文件? Path file=Path.get(“c:/large.log”); AsynchronousFileChannel=AsynchronousFileChannel.open(文件); 最终ByteBuffer缓冲区=ByteBuffer.allocate(1000); 通道读取(缓冲区,0,缓冲区, 新的CompletionHandler(){ 已完成公共作废(整数结果,ByteBuffer附件){ System.out.println(新字符串(buffer.array()); } });,io,java-7,nio2,Io,Java 7,Nio2,通过这种方式,我可以从large.log读取第一个1000字节。如果我不想像ByteBuffer.allocate(1000*1000)那样分配更大的字节数组,我如何读取下面的日志。因为我认为这会导致记忆的流失 有人能给我示例代码吗? 谢谢 ps:我可以使用JIO循环读取大文件,因为我可以检查java.io.BufferedReader.read()的返回值。但是我不知道如何使用NIO2。如果文件中还有剩余内容,请在completionHandler中启动另一次读取。但我会使用比1000大得多的

通过这种方式,我可以从large.log读取第一个1000字节。如果我不想像ByteBuffer.allocate(1000*1000)那样分配更大的字节数组,我如何读取下面的日志。因为我认为这会导致记忆的流失

有人能给我示例代码吗? 谢谢


ps:我可以使用JIO循环读取大文件,因为我可以检查java.io.BufferedReader.read()的返回值。但是我不知道如何使用NIO2。

如果文件中还有剩余内容,请在completionHandler中启动另一次读取。但我会使用比1000大得多的缓冲区,至少8192个。

这里有一个可行的方法

您需要注意以下几点:

  • 我刚刚使用了您的
    buffer.array()
    作为输出。我必须使用buffer.clear()重置位置,以便异步读取将看到有1000个备用字节,但这并不能从数组中清除现有数据。因此,当您在文件末尾时,如果读取的字节少于1000字节,它将打印整个缓冲区:不管您刚才读取了多少,加上缓冲区末尾剩余的1000字节。在现实生活中,您可能希望对此做些什么(可能是结果或缓冲区的位置)
  • 由于种种原因,我无法在
    completed
    方法中找出
    buffer
    这是一个类变量,但是
    channel
    这也是一个类变量,它是空的。我还没有弄清楚为什么会是空的。所以我更改了它,使它将
    channel
    作为附件而不是缓冲区传递。仍然没有我觉得很有道理
  • 异步读取线程的重要性不足以保持jvm运行。因此,我只是在主方法的末尾添加了一个
    read
    。按
    Enter
    退出
  • 类变量
    pos
    维护您正在读取的文件中的位置
  • 当您在
    complete
    方法中启动另一个异步读取时,神奇的事情就发生了。这就是为什么我放弃了匿名类并实现了接口本身
  • 您需要将路径切换回您的路径
  • 玩得开心

      Path file = Paths.get("c:/large.log");
      AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
      final ByteBuffer buffer = ByteBuffer.allocate(1000);
      channel.read(buffer, 0, buffer,
          new CompletionHandler<Integer, ByteBuffer>() {
            public void completed(Integer result, ByteBuffer attachment) {
              System.out.println(new String(buffer.array()));
            }
      }); 
    
    import java.nio.*;
    导入java.nio.channels.*;
    导入java.nio.file.*;
    导入java.io.IOException;
    公共类TryNio实现CompletionHandler{
    //需要跟踪下一个位置。
    int pos=0;
    AsynchronousFileChannel通道=空;
    ByteBuffer缓冲区=null;
    公共无效已完成(整数结果,异步文件通道附件){
    //若结果为-1,则表示未读取任何内容。
    如果(结果!=-1){
    pos+=result;//不要再读取相同的文本。
    //您的输出命令。
    System.out.println(新字符串(buffer.array());
    buffer.clear();//重置缓冲区,以便阅读更多内容。
    }
    //使用此命令启动另一个异步读取。
    附件。读取(缓冲区、pos、附件、本);
    }
    公共作废失败(可丢弃的exc,
    异步文件通道(附件){
    System.err.println(“错误!”);
    exc.printStackTrace();
    }
    公共无效doit(){
    Path file=Path.get(“/var/log/syslog”);
    AsynchronousFileChannel通道=空;
    试一试{
    channel=AsynchronousFileChannel.open(文件);
    }捕获(IOE异常){
    System.err.println(“无法打开文件:+file.toString());
    系统。出口(1);//是的,呵呵。
    }
    缓冲区=字节缓冲区分配(1000);
    //启动异步读取。
    通道读取(缓冲器、pos、通道、本机);
    //这个方法现在退出,线程返回main并等待用户输入。
    }
    公共静态void main(字符串[]args){
    TryNio tn=新TryNio();
    tn.doit();
    //等待fur用户按键,否则java将退出,因为
    //异步线程不够重要,无法保持其运行。
    请尝试{System.in.read();}捕获(IOE异常){}
    }
    }
    
    使用文件中的位置和文件大小,需要在completionhandler中重复调用异步读取操作以读取整个文件。每次读取操作完成时,需要使用红色字节数增加位置

    下面是completionhandler异步读取整个文件的完整方法。有关完整示例,请参阅


    GregHNZ解决方案非常好,因为我必须在不同的项目中多次使用此类代码,所以我最终将其放入了一个辅助库
    RxIo
    ,我在Maven Central Repository中发布了该库,github Repository中也提供了该库。使用该工具,您可以读取文件的所有字节,如:

    public void completed(Integer result, ByteBuffer attachment) {
        try {
            bb.flip();
            System.out.println("bytea red "+bb.limit());
    
            if(afc.size() > position) {
                position = position + bb.limit();
                bb.clear();
                //pass the same completion handler
                afc.read(bb, position, bb, this);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }       
    }
    
    分配默认大小为262144的
    ByteBuffer
    ,但您可以使用
    readAllBytes(路径文件,int-bufferSize)
    指定不同的值


    您可以在中看到其他用例。

    对我有效。当然,您必须清除缓冲区,并在读取中增加position参数,因此最终变量有点混乱,但这是可以做到的。我已经执行了此示例代码。Bu
    public void completed(Integer result, ByteBuffer attachment) {
        try {
            bb.flip();
            System.out.println("bytea red "+bb.limit());
    
            if(afc.size() > position) {
                position = position + bb.limit();
                bb.clear();
                //pass the same completion handler
                afc.read(bb, position, bb, this);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }       
    }
    
    AsyncFiles
        .readAllBytes(Paths.get("input.txt"))
        .thenApply(bytes -> { /*... use bytes... */});