我的大型机数据文件大于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();
}
}
}
你能帮我解决一下吗?
答案 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())
代替。