【问题标题】:Java Code for writing Long Array to file [closed]用于将长数组写入文件的 Java 代码 [关闭]
【发布时间】:2012-07-07 06:35:57
【问题描述】:

我从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!");
    };

}

【问题讨论】:

  • 要筛选的代码很多。你能告诉我们至少发生了什么错误吗?
  • @corsiKa,写数组和读数组不一样会报错。
  • ,想想它是如何工作的,我会暗示最明显的 '>3' 必须是 ...,sizeof(long)==8 而不是 4等。
  • @corsiKa,错误很明显,如果你运行它,实际上它在屏幕上也是可见的。
  • @bestsss 这个错误可能很明显,只是如果 OP 说有错误,他通常应该把错误放在帖子中。

标签: java


【解决方案1】:

所以我花了几分钟来实际运行代码,并且对您发布的代码进行了一些调整,但就是这样。

我做的一件事是 - 不必要 - 将 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);

在上面的 sn-p 中,我将膨胀缓冲区的长度更改为 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();

这是一个非常重要的变化。首先名称被更改,但这不是重要的部分。其次,正如 bestsss 指出的那样,remaining() 是 7 而不是 3。最后,a[i] 现在是 long 而不是 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 中,以防你弄乱了 diff 符号之类的东西:http://pastebin.com/emY14Ji4

注意:由于我没有删除调试语句,我的副本 (+) 中的行号比您的副本 (-) 高一...哎呀...

【讨论】:

  • 非常感谢。它工作正常。我无法从讨论中得到一件事,桶大小是否对性能有影响?
  • 其实我要写2.2亿个Int/Long,为此上面的代码有点慢。所以,很困惑。
  • 看起来代码的当前工作方式,将bucketsize减少到非常小的东西,比如说1&lt;&lt;5只会让你一次带入的项目更少,所以它会更慢。我对其进行了一些小的修改,以便可以将1&lt;&lt;x 数字作为参数传递。结果pastebin.com/sVX6FB0v 表明,在1&lt;&lt;10 之后,您不会获得显着、可靠的性能。
  • 如果您在 32 位机器上运行,此代码将比 int 代码慢。与 int 在 32 位机器(或在 64 位机器上运行的 32 位程序)相比,long 需要更长的时间。除非您使用 64 位硬件和软件,否则使用基于 int 的代码会更快。跨度>
  • 总是在更改代码时更改相关的 cmets。
【解决方案2】:

不要使用字节缓冲区,而是使用 ObjectOutputStream 将验证数据存储到文件中,并使用 ObjectInputStream 从中读取。我认为问题在于您在整个过程中没有持有“长期”定义。

ObjectOutputStream 和 ObjectInputStream 可以读取/写入任何数据类型。

【讨论】:

  • 对不起。我需要修改上面的代码,因此它可以工作很长时间。我需要用其他写/读方法检查性能。
  • 答案无论如何都不对。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-23
  • 2010-10-05
  • 2012-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多