我从here获得了一个代码来写一个Int数组到文件。但是,我正在尝试转换它,因此它可以将Long数组写入文件。但是,它给出了错误(下面给出的代码)。任何人都可以帮助我为什么它会给出错误以及应该更正的代码。感谢。
import java.io.*;
import java.util.ArrayList;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Random;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
public class Test {
private static final int bucketSize = 1<<17;//in real world should not be const, but we bored horribly
static final int zipLevel = 2;//feel free to experiement, higher compression (5+)is likely to be total waste
static void writes(long[] a, File file, boolean sync) throws IOException{
byte[] bucket = new byte[Math.min(bucketSize, Math.max(1<<13, Integer.highestOneBit(a.length >>3)))];//128KB bucket
byte[] zipOut = new byte[bucket.length];
final FileOutputStream fout = new FileOutputStream(file);
FileChannel channel = fout.getChannel();
try{
ByteBuffer buf = ByteBuffer.wrap(bucket);
//unfortunately java.util.zip doesn't support Direct Buffer - that would be the perfect fit
ByteBuffer out = ByteBuffer.wrap(zipOut);
out.putLong(a.length);//write length aka header
if (a.length==0){
doWrite(channel, out, 0);
return;
}
Deflater deflater = new Deflater(zipLevel, false);
try{
for (int i=0;i<a.length;){
i = puts(a, buf, i);
buf.flip();
deflater.setInput(bucket, buf.position(), buf.limit());
if (i==a.length)
deflater.finish();
//hacking and using bucket here is tempting since it's copied twice but well
for (int n; (n= deflater.deflate(zipOut, out.position(), out.remaining()))>0;){
doWrite(channel, out, n);
}
buf.clear();
}
}finally{
deflater.end();
}
}finally{
if (sync)
fout.getFD().sync();
channel.close();
}
}
static long[] reads(File file) throws IOException, DataFormatException{
FileChannel channel = new FileInputStream(file).getChannel();
try{
byte[] in = new byte[(int)Math.min(bucketSize, channel.size())];
ByteBuffer buf = ByteBuffer.wrap(in);
channel.read(buf);
buf.flip();
long[] a = new long[(int)buf.getLong()];
if (a.length==0)
return a;
int i=0;
byte[] inflated = new byte[Math.min(1<<17, a.length*4)];
ByteBuffer intBuffer = ByteBuffer.wrap(inflated);
Inflater inflater = new Inflater(false);
try{
do{
if (!buf.hasRemaining()){
buf.clear();
channel.read(buf);
buf.flip();
}
inflater.setInput(in, buf.position(), buf.remaining());
buf.position(buf.position()+buf.remaining());//simulate all read
for (;;){
int n = inflater.inflate(inflated,intBuffer.position(), intBuffer.remaining());
if (n==0)
break;
intBuffer.position(intBuffer.position()+n).flip();
for (;intBuffer.remaining()>3 && i<a.length;i++){//need at least 4 bytes to form an int
a[i] = intBuffer.getInt();
}
intBuffer.compact();
}
}while (channel.position()<channel.size() && i<a.length);
}finally{
inflater.end();
}
// System.out.printf("read ints: %d - channel.position:%d %n", i, channel.position());
return a;
}finally{
channel.close();
}
}
private static void doWrite(FileChannel channel, ByteBuffer out, int n) throws IOException {
out.position(out.position()+n).flip();
while (out.hasRemaining())
channel.write(out);
out.clear();
}
private static int puts(long[] a, ByteBuffer buf, int i) {
for (;buf.hasRemaining() && i<a.length;){
buf.putLong(a[i++]);
}
return i;
}
private static long[] generateRandom(int len){
Random r = new Random(17);
long[] n = new long [len];
for (int i=0;i<len;i++){
n[i]= r.nextBoolean()?0: r.nextInt(1<<23);//limit bounds to have any sensible compression
}
return n;
}
public static void main(String[] args) throws Throwable{
File file = new File("xxx.xxx");
long[] n = generateRandom(3000000); //{0,2,4,1,2,3};
long start = System.nanoTime();
writes(n, file, false);
long elapsed = System.nanoTime() - start;//elapsed will be fairer if the sync is true
System.out.printf("File length: %d, for %d ints, ratio %.2f in %.2fms %n", file.length(), n.length, ((double)file.length())/4/n.length, java.math.BigDecimal.valueOf(elapsed, 6) );
long[] m = reads(file);
//compare, Arrays.equals doesn't return position, so it sucks/kinda
for (int i=0; i<n.length; i++){
if (m[i]!=n[i]){
System.err.printf("Failed at %d%n",i);
break;
}
}
System.out.printf("All done!");
};
}
答案 0 :(得分:2)
所以我花了几分钟时间来实际运行代码,并且从你发布的代码中进行了一些调整,但现在是。
我做的一件事是 - 不必要 - 是将intBuffer
改为longBuffer
,只是为了清楚起见。这是第一个差异的一部分
75 - byte[] inflated = new byte[Math.min(1<<17, a.length*4)];
76 - ByteBuffer intBuffer = ByteBuffer.wrap(inflated);
76 + byte[] inflated = new byte[Math.min(1<<17, a.length*8)];
77 + ByteBuffer longBuffer = ByteBuffer.wrap(inflated);
在上面的代码片段中,我将膨胀缓冲区的长度更改为a.length * 8,以反映它是一个长数组而不是一个int数组。
89 - int n = inflater.inflate(inflated,intBuffer.position(), intBuffer.remaining());
90 + int n = inflater.inflate(inflated,longBuffer.position(), longBuffer.remaining());
这只是对变量名称的更改。
92 - intBuffer.position(intBuffer.position()+n).flip();
93 - for (;intBuffer.remaining()>3 && i<a.length;i++){//need at least 4 bytes to form an int
94 - a[i] = intBuffer.getInt();
93 + longBuffer.position(longBuffer.position()+n).flip();
94 + for (;longBuffer.remaining()>7 && i<a.length;i++){//need at least 4 bytes to form an int
95 + a[i] = longBuffer.getLong();
这是一个非常重要的变化。首先,名称已更改,但这不是重要部分。其次,remaining()
是7而不是3,正如最好的指出的那样。最后, a [i]现在变长了而不是int。。这肯定是最大的问题。
96 - intBuffer.compact();
97 + longBuffer.compact();
这里只是重命名。
142 - System.out.printf("File length: %d, for %d ints, ratio %.2f in %.2fms %n", file.length(), n.length, ((double)file.length())/4/n.length, java.math.BigDecimal.valueOf(elapsed, 6) );
143 + System.out.printf("File length: %d, for %d ints, ratio %.2f in %.2fms %n", file.length(), n.length, ((double)file.length())/8/n.length, java.math.BigDecimal.valueOf(elapsed, 6) );
这只是在文件输出上,以了解压缩,它现在计算file.length / 8而不是4的结果数。
这些是我必须做的唯一必要的编辑才能让它发挥作用。基本上只是在所有地方从int移动到long。
完整代码位于pastebin中,以防您滥用差异符号或其他内容:http://pastebin.com/emY14Ji4
注意:我的副本(+)中的行号比副本( - )高一个,因为我没有删除调试语句...哎呀...
答案 1 :(得分:-1)
不要使用字节缓冲区,而是使用ObjectOutputStream将veriable存储到文件中,并使用ObjectInputStream从中读取。我认为问题是你在整个过程中没有持有“长”的定义。
ObjectOutputStream和ObjectInputStream可以读/写任何数据类型。