在Java中将整数数组写入文件的最快方法?

正如标题所说,我正在寻找将整数数组写入文件的最快方法。 这些arrays的大小会有所不同,实际上可以包含2500到25 000 000个整数。

这是我目前使用的代码:

DataOutputStream writer = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(filename))); for (int d : data) writer.writeInt(d); 

鉴于DataOutputStream有一个写字节数组的方法,我尝试将int数组转换为如下字节数组:

 private static byte[] integersToBytes(int[] values) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); for (int i = 0; i < values.length; ++i) { dos.writeInt(values[i]); } return baos.toByteArray(); } 

并像这样:

 private static byte[] integersToBytes2(int[] src) { int srcLength = src.length; byte[] dst = new byte[srcLength << 2]; for (int i = 0; i < srcLength; i++) { int x = src[i]; int j = i <>> 0) & 0xff); dst[j++] = (byte) ((x >>> 8) & 0xff); dst[j++] = (byte) ((x >>> 16) & 0xff); dst[j++] = (byte) ((x >>> 24) & 0xff); } return dst; } 

两者似乎都给出了一个小幅度的提升,约为5%。 我没有严格测试它们来证实这一点。

是否有任何技术可以加快此文件写入操作,或者是Java IO写入性能最佳实践的相关指南?

我看了三个选项:

  1. 使用DataOutputStream ;
  2. 使用ObjectOutputStream (对于Serializable对象,其中int[]是); 和
  3. 使用FileChannel

结果是

 DataOutputStream wrote 1,000,000 ints in 3,159.716 ms ObjectOutputStream wrote 1,000,000 ints in 295.602 ms FileChannel wrote 1,000,000 ints in 110.094 ms 

所以NIO版本是最快的。 它还具有允许编辑的优点,这意味着您可以轻松地更改一个int,而ObjectOutputStream需要读取整个数组,修改它并将其写入文件。

代码如下:

 private static final int NUM_INTS = 1000000; interface IntWriter { void write(int[] ints); } public static void main(String[] args) { int[] ints = new int[NUM_INTS]; Random r = new Random(); for (int i=0; i 

我会使用nio包和ByteBuffer FileChannel 。 这种方法似乎(在我的计算机上)提高了2到4倍的写入性能

程序输出:

 normal time: 2555 faster time: 765 

这是该计划:

 public class Test { public static void main(String[] args) throws IOException { // create a test buffer ByteBuffer buffer = createBuffer(); long start = System.currentTimeMillis(); { // do the first test (the normal way of writing files) normalToFile(new File("first"), buffer.asIntBuffer()); } long middle = System.currentTimeMillis(); { // use the faster nio stuff fasterToFile(new File("second"), buffer); } long done = System.currentTimeMillis(); // print the result System.out.println("normal time: " + (middle - start)); System.out.println("faster time: " + (done - middle)); } private static void fasterToFile(File file, ByteBuffer buffer) throws IOException { FileChannel fc = null; try { fc = new FileOutputStream(file).getChannel(); fc.write(buffer); } finally { if (fc != null) fc.close(); buffer.rewind(); } } private static void normalToFile(File file, IntBuffer buffer) throws IOException { DataOutputStream writer = null; try { writer = new DataOutputStream(new BufferedOutputStream( new FileOutputStream(file))); while (buffer.hasRemaining()) writer.writeInt(buffer.get()); } finally { if (writer != null) writer.close(); buffer.rewind(); } } private static ByteBuffer createBuffer() { ByteBuffer buffer = ByteBuffer.allocate(4 * 25000000); Random r = new Random(1); while (buffer.hasRemaining()) buffer.putInt(r.nextInt()); buffer.rewind(); return buffer; } } 

我认为你应该考虑使用文件通道(java.nio库)而不是普通流(java.io)。 一个很好的起点是这个有趣的讨论: Java NIO FileChannel与FileOutputstream的性能/实用性

以及下面的相关评论。

干杯!

编写int []的主要改进是:

  • 增加缓冲区大小。 大小适合大多数流,但使用更大的缓冲区可以更快地访问文件。 这可以产生10-20%的改善。

  • 使用NIO和直接缓冲区。 这允许您编写32位值而无需转换为字节。 这可能会带来5%的改善。

顺便说一句:你应该能够每秒写入至少1000万个int值。 使用磁盘缓存,您可以将其增加到每秒2亿。

数组是Serializable – 你不能只使用writer.writeObject(data); ? 这writeInt单个writeInt调用更快。

如果您对输出数据格式有其他要求而不是检索到int[] ,那么这是一个不同的问题。