java - 在java中读取文件> 4GB文件

标签 java stream nio

我有大于 4GB 的大型机数据文件。我需要读取和处理每 500 个字节的数据。我已经尝试使用 FileChannel,但是我收到错误消息 Integer.Max_VALUE exceeded

public void getFileContent(String fileName) {
    RandomAccessFile aFile = null;
    FileChannel inChannel = null;
    try {
        aFile = new RandomAccessFile(Paths.get(fileName).toFile(), "r");
        inChannel = aFile.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(500 * 100000);
        while (inChannel.read(buffer) > 0) {
            buffer.flip();
            for (int i = 0; i < buffer.limit(); i++) {
                byte[] data = new byte[500];
                buffer.get(data);
                processData(new String(data));
                buffer.clear();
            }
        }
    } catch (Exception ex) {
        // TODO
    } finally {
        try {
            inChannel.close();
            aFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

你能帮我解决一下吗?

最佳答案

你的代码最糟糕的问题是

catch (Exception ex) {
    // TODO
}

部分,这意味着您不会注意到代码抛出的任何异常。由于 JRE 中没有打印“Integer.Max_VALUE exceeded”消息,因此该问题必须与您的 processData 方法有关。

可能值得注意的是,对于重复数据,此方法将被过于频繁地调用。

你的循环

for (int i = 0; i < buffer.limit(); i++) {

表示您迭代的次数与缓冲区中的字节数一样多,最多 500 * 100000 次。您在每次迭代中从缓冲区中提取 500 字节,每次 read 后总共处理最多 500 * 500 * 100000 字节,但是由于您在循环体末尾错放了一个 buffer.clear();,因此您永远不会遇到 BufferUnderflowException。相反,您将使用缓冲区的前 500 字节调用 processData 每次最多 500 * 100000 次。

但是从字节到 String 的整个转换是不必要的冗长并且包含不必要的复制操作。您可以而且应该只使用 Reader 而不是自己实现它。

除此之外,您的代码绕了一个奇怪的弯路。它以 Java 7 API Paths.get 开始,将其转换为遗留 File 对象,创建遗留 RandomAccessFile 以最终获取一个文件 channel 。如果你有一个 Path 并且想要一个 FileChannel,你应该直接通过 FileChannel.open 打开它。 .当然,使用 try(…) { … } 语句来确保正确关闭。

但是,如前所述,如果您想将内容作为 String 进行处理,您肯定想改用 Reader:

public void getFileContent(String fileName) {
    try( Reader reader=Files.newBufferedReader(Paths.get(fileName)) ) {
        CharBuffer buffer = CharBuffer.allocate(500 * 100000);
        while(reader.read(buffer) > 0) {
            buffer.flip();
            while(buffer.remaining()>500) {
                processData(buffer.slice().limit(500).toString());
                buffer.position(buffer.position()+500);
            }
            buffer.compact();
        }
        // there might be a remaining chunk of less than 500 characters
        if(buffer.position()>0) {
            processData(buffer.flip().toString());
        }
    } catch(Exception ex) {
        // the *minimum* to do:
        ex.printStackTrace();
        // TODO real exception handling
    }
}

处理>4GB的文件没有问题,我刚用8GB的文件测试过。请注意,上面的代码使用了 UTF-8 编码。如果您想保留使用系统默认编码的原始代码的行为,您可以使用

创建Reader
Files.newBufferedReader(Paths.get(fileName), Charset.defaultCharset())

相反。

关于java - 在java中读取文件> 4GB文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37836722/

相关文章:

java - 如何使用 java.nio.channels.FileChannel 读取 ByteBuffer 实现类似 BufferedReader#readLine() 的行为

java - 方法内的访问修饰符

c# - 从 C# 中的未知长度流计算散列

c++ - Ho 得到一个字符串,直到一个字符的最后一次出现

c++ - 从 .txt 文件读取数据并放入 vector 时,Linux 比 Windows 快得多。我将如何加速 Windows 来做同样的事情?

java - 为什么我应该将 NIO 用于 TCP 多人游戏而不是简单的套接字 (IO) - 或 : where is the block?

java - 将 netty 与 Web 容器集成

Java 数组拆分和重新连接。丢失的元素

javascript - 如何进行bean验证

java - 如何将图像位置发送到 fragment 中的另一个 Activity ?