Fast way to compare inputstreams

后端 未结 4 2049

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) thr         


        
相关标签:
4条回答
  • 2021-02-05 05:37

    By far my favorite is to use the org.apache.commons.io.IOUtils helper class from the Apache Commons IO library:

    IOUtils.contentEquals( is1, is2 );
    
    0 讨论(0)
  • 2021-02-05 05:39

    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();
        }
    }
    
    0 讨论(0)
  • 2021-02-05 05:43

    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.

    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();
        }
    }
    
    0 讨论(0)
  • 2021-02-05 05:51

    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 GitHub or from Sonatype's OSS Snapshot Repository Maven:

    <dependency>
      <groupId>at.molindo</groupId>
      <artifactId>molindo-utils</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
    
    0 讨论(0)
提交回复
热议问题