在Java中读取二进制文件

13

我有一个包含无符号整数的相对较长的文件(每个数字有64位,文件大小为0.47GB),我需要读取并存储到一个数组中。在一番思索后,我最终选择了使用long类型,因为在Java中所有东西都是有符号的(如果我错了,请指出)。无论如何,这个数组只需要排序,所以原始数字的确切值并不是最重要的。我们只需要测量排序算法的效率,没有其他更多的需求。然而,当我真正开始读取文件时(参见下面的代码),我遇到了一些困难。

public class ReadFileTest {
    public static void main(String[] args) throws Exception {
        String address = "some/directory";
        File input_file = new File (address);
        FileInputStream file_in = new FileInputStream(input_file);
        DataInputStream data_in = new DataInputStream (file_in );

        long [] array_of_ints = new long [1000000];
        int index = 0;

        long start = System.currentTimeMillis();

        while(true) {
            try {
                long a = data_in.readLong();
                index++;
                System.out.println(a);
            }
            catch(EOFException eof) {
                System.out.println ("End of File");
                break;
            }
        }

        System.out.println(index);
        System.out.println(System.currentTimeMillis() - start);
    }
}

程序似乎永远在运行,通常我会趁着它读取的时候出去吃午饭。到目前为止,最快的速度是20分钟。今天一位同学吹嘘他的程序只用了4秒钟。他使用的是C++,我知道C++比Java更快,但这也太离谱了。请问有人能告诉我我在这里做错了什么吗?我不能把它归咎于语言或机器,所以必须是我的问题。从我看到的情况来看,Java教程使用的正是相同的类,即DataInputStream。另外,我还看到一些人推荐使用FileChannels,难道这是唯一的出路吗?


6
你的同伴程序是否也将所有内容打印到标准输出?我敢打赌大部分时间都花在那里了。在读取循环中注释掉println语句,然后再试一遍。 - Ingo
2
请确保您使用与他相同的设置。如果您使用的是5400 RPM硬盘,而他使用的是SSD,无论您使用什么语言,他都会比您快得多。 - DHall
你每天吃几顿饭?(开个玩笑) - asgs
另外,对于您的0.47 GB文件,您可能希望使用更长的数组。您可以尝试使用inputFile.getLength()/8作为数组的长度。 - Paŭlo Ebermann
2个回答

17

你应该使用缓冲输入,类似于:

new DataInputStream(
    new BufferedInputStream(
        new FileInputStream(new File(input_file))))

4
尝试使用不同大小的缓冲区。不要假设默认缓冲区大小是最好的,特别是当你读取如此大量的字节时。 - Kelly S. French
通常情况下,即使在本地语言中,我也发现将缓冲区增加到默认值8192以上并不能帮助太多。拥有几十或几百字节的非常小的缓冲区会导致速度变慢,但一旦达到8192,您可能已经获得了最大性能的90%或更多。 - BeeOnRope

2

想要获取文件的对象:

new ObjectInputStream(
    new BufferedInputStream(
        new FileInputStream(new File(file_name))))

更多关于两者之间的区别

(注:本文涉及IT技术)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接