Java读写大型长数组代码
我正在尝试将一个大小为400000000的长数组写入一个文件,然后将其读回。我使用的代码如下:
import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
import java.io.RandomAccessFile ;
import java.util.* ;
class Checks {
public static FileChannel channel;
public static MappedByteBuffer mbb;
public static void main(String[] args){
try{
long k[] = new long[400000000] ;
for(int i = 0 ; i < 400000000 ; i++){
k[i] = i ;
}
channel = new RandomAccessFile("abc.dat", "rw").getChannel();
mbb = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1 << 24);
mbb.order(ByteOrder.nativeOrder());
for(int i = 0 ; i < 400000000 ;i++ ){
getMbb().putLong(k[i]);
}
channel.close();
long ks[] = new long[400000000] ;
channel = new RandomAccessFile("abc.dat", "rw").getChannel();
mbb = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1 << 24);
mbb.order(ByteOrder.nativeOrder());
for(int r = 0 ; r < 400000000; r++){
ks[r] = getMbb().getLong();
}
for(int r = 0 ; r < 400000000; r++){
if(k[r] != ks[r]){
System.out.println("Error at " + r);
break ;
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static ByteBuffer getMbb() throws IOException {
if (mbb.remaining() <= 0) {
mbb = channel.map(FileChannel.MapMode.READ_WRITE, channel.size(), 1 << 24);
mbb.order(ByteOrder.nativeOrder());
}
return mbb;
}
}
然而,这段代码给出的错误是,写入数组和读取数组不一样。谁能帮帮我为什么会这样
# 1 楼答案
我觉得你的
getMbb()
方法坏了。每次在内存中重新映射文件块时,都会映射到channel.size()
。这只在创建文件时有效,但在读取文件时无效。在读取文件时,映射文件末尾之后的文件“区域”,该区域包含随机内容您必须修复重新映射代码,以跟踪文件中已存在的位置
# 2 楼答案
以下是我的建议:
这是程序的全部功能,但不需要显式分配内存,当然也不需要通过内存映射缓冲区重复分配。 如果这个解决方案真的适用于你真正想做的事情,很难说,因为你没有说这是为了什么
# 3 楼答案
在关闭通道之前,请尝试强制对映射到磁盘的缓冲区进行更改:
这样,如果使用存储在本地设备上的文件,可以保证对映射缓冲区所做的所有更改都会反映在磁盘上
考虑到您只在文件中附加内容,实现所需内容的另一种方法是:
阅读:
关于性能:在执行I/O的应用程序中,性能损失取决于搜索次数。因此,搜索次数越少,性能越高。这相当于以顺序的方式将尽可能多的数据写入(<;=>;较小的磁盘刷新次数;实际上,刷新意味着查找)
在您的场景中,数据仅以顺序方式写入(附加到文件),因此唯一需要担心的是磁盘刷新的数量;这个数字与缓冲区的大小成反比。所以你应该尽量增加缓冲区的大小
# 4 楼答案
我对你的代码做了一些修改,用DataInputStream和DataOutputStream代替了RandomAccessFile,效果很好