我有大于 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/