【问题标题】:Reading file >4GB file in java在java中读取文件> 4GB文件
【发布时间】:2023-04-11 12:39:02
【问题描述】:

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

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();
        }
    }
}

你能帮我解决一下吗?

【问题讨论】:

  • 显示异常和堆栈跟踪
  • 您可以尝试用BufferedInputStream 包裹FileInputStream
  • 看看这个 -> stackoverflow.com/questions/8076472/… 会给你一个关于你遇到的错误的想法
  • 顺便说一句,考虑使用try-with-resources,对于可关闭的资源管理更方便
  • 如果您要解析字符,为什么不直接使用阅读器?例如,try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName))) { … }

标签: java stream nio


【解决方案1】:

你的代码最糟糕的问题是

catch (Exception ex) {
    // TODO
}

part,这意味着您不会注意到代码抛出的任何异常。由于 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 以最终获取 FileChannel。如果你有一个Path 并且想要一个FileChannel,你应该直接通过FileChannel.open 打开它。当然,使用try(…) { … } 语句来确保正确关闭。

但是,如前所述,如果您想将内容处理为Strings,您肯定希望使用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())

改为。

【讨论】:

    猜你喜欢
    • 2014-09-28
    • 2010-09-22
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    相关资源
    最近更新 更多