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

时间:2016-06-15 13:21:28

标签: java stream nio

我的大型机数据文件大于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();
        }
    }
}

你能帮我解决一下吗?

1 个答案:

答案 0 :(得分:3)

代码中最严重的问题是

catch (Exception ex) {
    // TODO
}

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

值得注意的是,重复数据会经常调用此方法。

你的循环

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

意味着您迭代缓冲区中的字节数次,最多500 * 100000次。您在每次迭代中从缓冲区中提取500个字节,在每个500 * 500 * 100000之后处理总共最多read个字节,但是因为最后有一个错误的buffer.clear();在循环体中,你永远不会遇到BufferUnderflowException。相反,您将使用缓冲区的第一个processData字节调用500 * 100000每个最多500次。

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

,而不是自己实现

除此之外,你的代码绕道而行。它从Java 7 API Paths.get开始,将其转换为旧File对象,创建遗留RandomAccessFile以最终获得FileChannel。如果您有Path并想要FileChannel,则应直接通过FileChannel.open打开它。当然,使用try(…) { … }语句来确保正确关闭。

但是,如上所述,如果您要将内容处理为String s,那么您肯定想要使用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
    }
}

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

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

代替。