Java 比较输入流的快速方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4245863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Fast way to compare inputstreams
提问by dacwe
I have a problem, I need to compare two inputstreams fast.
我有一个问题,我需要快速比较两个输入流。
Today I have a function like this:
今天我有一个这样的功能:
private boolean isEqual(InputStream i1, InputStream i2) throws IOException {
try {
// do the compare
while (true) {
int fr = i1.read();
int tr = i2.read();
if (fr != tr)
return false;
if (fr == -1)
return true;
}
} finally {
if (i1 != null)
i1.close();
if (i2 != null)
i2.close();
}
}
But it's really slow. I want to use buffered reads but have not come up with a good way of doing it.
但它真的很慢。我想使用缓冲读取,但还没有想出一个好的方法。
Some extra stuff that makes it harder:
一些额外的东西让它变得更难:
- I don't want to read one of the input streams into memory (the whole one)
- I don't want to use a third party library
- 我不想将输入流之一读入内存(整个)
- 我不想使用第三方库
I need a practial solution - code! :)
我需要一个实用的解决方案 - 代码!:)
采纳答案by aioobe
Something like this may do:
像这样的事情可能会做:
private static boolean isEqual(InputStream i1, InputStream i2)
throws IOException {
ReadableByteChannel ch1 = Channels.newChannel(i1);
ReadableByteChannel ch2 = Channels.newChannel(i2);
ByteBuffer buf1 = ByteBuffer.allocateDirect(1024);
ByteBuffer buf2 = ByteBuffer.allocateDirect(1024);
try {
while (true) {
int n1 = ch1.read(buf1);
int n2 = ch2.read(buf2);
if (n1 == -1 || n2 == -1) return n1 == n2;
buf1.flip();
buf2.flip();
for (int i = 0; i < Math.min(n1, n2); i++)
if (buf1.get() != buf2.get())
return false;
buf1.compact();
buf2.compact();
}
} finally {
if (i1 != null) i1.close();
if (i2 != null) i2.close();
}
}
回答by Peter Lawrey
Using buffered reads is just a matter of wrapping the InputStreams with BufferedInputStreams. However you are likely to get the best performance reading large blocks at a time.
使用缓冲读取只是用 BufferedInputStreams 包装 InputStreams 的问题。但是,一次读取大块可能会获得最佳性能。
private boolean isEqual(InputStream i1, InputStream i2) throws IOException {
byte[] buf1 = new byte[64 *1024];
byte[] buf2 = new byte[64 *1024];
try {
DataInputStream d2 = new DataInputStream(i2);
int len;
while ((len = i1.read(buf1)) > 0) {
d2.readFully(buf2,0,len);
for(int i=0;i<len;i++)
if(buf1[i] != buf2[i]) return false;
}
return d2.read() < 0; // is the end of the second file also.
} catch(EOFException ioe) {
return false;
} finally {
i1.close();
i2.close();
}
}
回答by sfussenegger
why not simply wrap both streams at the very beginning of your method:
为什么不简单地在方法的开头包装两个流:
i1 = new BufferedInputStream(i1);
i2 = new BufferedInputStream(i2);
Alternatively, you could simply try reading both streams into a buffer:
或者,您可以简单地尝试将两个流读入缓冲区:
public static boolean equals(InputStream i1, InputStream i2, int buf) throws IOException {
try {
// do the compare
while (true) {
byte[] b1 = new byte[buf];
byte[] b2 = new byte[buf];
int length = i1.read(b1);
if (length == -1) {
return i2.read(b2, 0, 1) == -1;
}
try {
StreamUtils.readFully(i2, b2, 0, length);
} catch (EOFException e) {
// i2 is shorter than i1
return false;
}
if (!ArrayUtils.equals(b1, b2, 0, length)) {
return false;
}
}
} finally {
// simply close streams and ignore (log) exceptions
StreamUtils.close(i1, i2);
}
}
// StreamUtils.readFully(..)
public static void readFully(InputStream in, byte[] b, int off, int len) throws EOFException, IOException {
while (len > 0) {
int read = in.read(b, off, len);
if (read == -1) {
throw new EOFException();
}
off += read;
len -= read;
}
}
// ArrayUtils.equals(..)
public static boolean equals(byte[] a, byte[] a2, int off, int len) {
if (off < 0 || len < 0 || len > a.length - off || len > a2.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return true;
}
if (a == a2) {
return true;
}
if (a == null || a2 == null) {
return false;
}
for (int i = off; i < off + len; i++) {
if (a[i] != a2[i]) {
return false;
}
}
return true;
}
EDIT: I've fixed my implementation now. That's how it looks like without DataInputStream or NIO. Code is available at GitHubor from Sonatype's OSS Snapshot RepositoryMaven:
编辑:我现在已经修复了我的实现。这就是没有 DataInputStream 或 NIO 时的样子。代码可在 GitHub或Sonatype 的 OSS Snapshot RepositoryMaven 中获得:
<dependency>
<groupId>at.molindo</groupId>
<artifactId>molindo-utils</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
回答by Snicolas
By far my favorite is to use the org.apache.commons.io.IOUtils
helper class from the Apache Commons IO library:
到目前为止,我最喜欢的是使用Apache Commons IO 库中的org.apache.commons.io.IOUtils
helper 类:
IOUtils.contentEquals( is1, is2 );