在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写入性能最佳实践的相关指南?
我看了三个选项:
- 使用
DataOutputStream
; - 使用
ObjectOutputStream
(对于Serializable
对象,其中int[]
是); 和 - 使用
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[]
,那么这是一个不同的问题。