我有一个二进制文件(约100 MB),需要快速读取。在C++中,我可以将文件加载到char指针中,并通过递增指针来遍历它。这当然非常快。
在Java中是否有类似的快速方法?
我有一个二进制文件(约100 MB),需要快速读取。在C++中,我可以将文件加载到char指针中,并通过递增指针来遍历它。这当然非常快。
在Java中是否有类似的快速方法?
如果您使用内存映射文件或常规缓冲区,则可以以硬件允许的速度读取数据。
File tmp = File.createTempFile("deleteme", "bin");
tmp.deleteOnExit();
int size = 1024 * 1024 * 1024;
long start0 = System.nanoTime();
FileChannel fc0 = new FileOutputStream(tmp).getChannel();
ByteBuffer bb = ByteBuffer.allocateDirect(32 * 1024).order(ByteOrder.nativeOrder());
for (int i = 0; i < size; i += bb.capacity()) {
fc0.write(bb);
bb.clear();
}
long time0 = System.nanoTime() - start0;
System.out.printf("Took %.3f ms to write %,d MB using ByteBuffer%n", time0 / 1e6, size / 1024 / 1024);
long start = System.nanoTime();
FileChannel fc = new FileInputStream(tmp).getChannel();
MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, size);
LongBuffer longBuffer = buffer.order(ByteOrder.nativeOrder()).asLongBuffer();
long total = 0; // used to prevent a micro-optimisation.
while (longBuffer.remaining() > 0)
total += longBuffer.get();
fc.close();
long time = System.nanoTime() - start;
System.out.printf("Took %.3f ms to read %,d MB MemoryMappedFile%n", time / 1e6, size / 1024 / 1024);
long start2 = System.nanoTime();
FileChannel fc2 = new FileInputStream(tmp).getChannel();
bb.clear();
while (fc2.read(bb) > 0) {
while (bb.remaining() > 0)
total += bb.get();
bb.clear();
}
fc2.close();
long time2 = System.nanoTime() - start2;
System.out.printf("Took %.3f ms to read %,d MB File via NIO%n", time2 / 1e6, size / 1024 / 1024);
打印
Took 305.243 ms to write 1,024 MB using ByteBuffer
Took 286.404 ms to read 1,024 MB MemoryMappedFile
Took 155.598 ms to read 1,024 MB File via NIO
这是针对一个比您所需的文件大10倍的情况。它之所以如此快,是因为数据被缓存在内存中(我有一块SSD硬盘)。如果您拥有快速的硬件,数据可以被读取得很快。
当然,你可以使用内存映射文件。
以下是两个带有示例代码的好链接:
InputStream
(例如在将其包装在BufferedInputStream
之后使用DataInputStream
)即可。大多数文件不需要内存映射,而可以通过标准Java I/O进行读取,特别是针对如此小的文件。使用BufferedInputStream是读取这些文件的合理方式。
InputStream in = new BufferedInputStream(new FileInputStream("somefile.ext"));
对于大多数计算机,Java已经对缓冲进行了优化。如果您有一个更大的文件,比如100MB,那么您可以考虑进一步优化。
在Java中如何将二进制文件读入字节数组,请参考这篇博客文章:
http://www.spartanjava.com/2008/read-a-file-into-a-byte-array/
复制自链接:
File file = new File("/somepath/myfile.ext");
FileInputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
if (length > Integer.MAX_VALUE) {
throw new IOException("The file is too big");
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("The file was not completely read: "+file.getName());
}
// Close the input stream, all file contents are in the bytes variable
is.close()
.read()
逐字节读取。它是指定剩余的文件大小,以便尽可能一次性读取。相信我,在一个100kb的文件上,这将非常快,并给他一个字节数组,以便他可以像在C++中一样迭代它。 - Paul从磁盘读取文件将是最慢的部分,因此它很可能不会有任何区别。当然,这个单独的操作- JVM仍需要十年才能启动,所以要加上这段时间。
在编程中,使用Java SDK的DataInputStream可能会很有帮助。如果需要读取字节或字符,DataInputStream提供了readByte()或readChar()等函数。
以下是一个简单的示例:
DataInputStream dis = new DataInputStream(new FileInputStream("file.dat"));
try {
while(true) {
byte b = dis.readByte();
//Do something with the byte
}
} catch (EOFException eofe) {
//Stream Ended
} catch (IOException ioe) {
//Input exception
}