garydgregory commented on a change in pull request #101: IO-649 - Improve the
performance of the contentEquals() methods.
URL: https://github.com/apache/commons-io/pull/101#discussion_r370778595
##########
File path: src/main/java/org/apache/commons/io/IOUtils.java
##########
@@ -691,80 +692,173 @@ public static void closeQuietly(final Writer output) {
}
/**
- * Compares the contents of two Streams to determine if they are equal or
- * not.
+ * Compares the contents of two Streams to determine if they are equal or
not.
* <p>
- * This method buffers the input internally using
- * <code>BufferedInputStream</code> if they are not already buffered.
- * </p>
+ * This method buffers the input internally using {@link
#DEFAULT_BUFFER_SIZE} sized buffers.
*
* @param input1 the first stream
* @param input2 the second stream
* @return true if the content of the streams are equal or they both don't
* exist, false otherwise
- * @throws NullPointerException if either input is null
* @throws IOException if an I/O error occurs
*/
@SuppressWarnings("resource")
public static boolean contentEquals(final InputStream input1, final
InputStream input2)
throws IOException {
+ return contentEquals(input1, input2, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Compares the contents of two Streams to determine if they are equal or
not.
+ * <p>
+ * This method buffers the input internally.
+ *
+ * @param input1 the first stream
+ * @param input2 the second stream
+ * @param bufferSize the size of the internal buffer to use.
+ * @return true if the content of the streams are equal or they both don't
+ * exist, false otherwise
+ * @throws IllegalArgumentException if bufferSize is less than or equal to
zero.
+ * @throws IOException if an I/O error occurs
+ * @since 2.6
+ */
+ @SuppressWarnings("resource")
+ public static boolean contentEquals(final InputStream input1, final
InputStream input2, final int bufferSize)
+ throws IOException {
+ if (bufferSize <= 0) {
+ throw new IllegalArgumentException("Buffer size must be positive:
" + bufferSize);
+ }
+
if (input1 == input2) {
return true;
}
if (input1 == null ^ input2 == null) {
return false;
}
- final BufferedInputStream bufferedInput1 = buffer(input1);
- final BufferedInputStream bufferedInput2 = buffer(input2);
- int ch = bufferedInput1.read();
- while (EOF != ch) {
- final int ch2 = bufferedInput2.read();
- if (ch != ch2) {
+
+ int input1NumBytesRead = 0;
+ int input2NumBytesRead = 0;
+ final byte[] input1Buffer = new byte[bufferSize];
+ final byte[] input2Buffer = new byte[bufferSize];
+ do {
+ input1NumBytesRead = fillBuffer(input1, input1Buffer);
+ input2NumBytesRead = fillBuffer(input2, input2Buffer);
+
+ if (input2NumBytesRead != input1NumBytesRead ||
!Arrays.equals(input1Buffer, input2Buffer)) {
return false;
}
- ch = bufferedInput1.read();
- }
- return bufferedInput2.read() == EOF;
+ } while (input1NumBytesRead == bufferSize && input2NumBytesRead ==
bufferSize);
+
+ return input1.read() == EOF && input2.read() == EOF;
}
+
/**
- * Compares the contents of two Readers to determine if they are equal or
- * not.
+ * This method fills the provided byte array buffer from the provided
<code>InputStream</code>. When this method
+ * returns the buffer will either be full or the InputStream will be fully
consumed.
+ *
+ * @param inputStream the InputStream from which to read
+ * @param buffer the buffer to fill
+ * @return the number of bytes placed in the buffer. If this is equal to
<code>buffer.length</code> then the
+ * buffer was completely filled. If it is less than
<code>buffer.length</code>, then the InputStream has been
+ * fully consumed.
+ * @throws IOException if an I/O error occurs.
+ */
+ private static int fillBuffer(final InputStream inputStream, final byte[]
buffer) throws IOException {
+ int totalBytesRead = 0;
+ int bytesRead = 0;
+ do {
+ totalBytesRead += bytesRead;
+ bytesRead = inputStream.read(buffer, totalBytesRead, buffer.length
- totalBytesRead);
+ } while (bytesRead != -1 && totalBytesRead < buffer.length);
+
+ return totalBytesRead;
+ }
+
+ /**
+ * Compares the contents of two Readers to determine if they are equal or
not.
* <p>
- * This method buffers the input internally using
- * <code>BufferedReader</code> if they are not already buffered.
+ * This method buffers the input internally using {@link
#DEFAULT_BUFFER_SIZE} sized buffers.
* </p>
*
* @param input1 the first reader
* @param input2 the second reader
* @return true if the content of the readers are equal or they both don't
* exist, false otherwise
- * @throws NullPointerException if either input is null
* @throws IOException if an I/O error occurs
* @since 1.1
*/
@SuppressWarnings("resource")
public static boolean contentEquals(final Reader input1, final Reader
input2)
throws IOException {
+ return contentEquals(input1, input2, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Compares the contents of two Readers to determine if they are equal or
not.
+ * <p>
+ * This method buffers the input internally.
+ * </p>
+ *
+ * @param input1 the first reader
+ * @param input2 the second reader
+ * @param bufferSize the size of the internal buffer to use.
+ * @return true if the content of the readers are equal or they both don't
+ * exist, false otherwise
+ * @throws IllegalArgumentException if bufferSize is less than or equal to
zero.
+ * @throws IOException if an I/O error occurs
+ * @since 2.6
+ */
+ @SuppressWarnings("resource")
+ public static boolean contentEquals(final Reader input1, final Reader
input2, final int bufferSize)
+ throws IOException {
+ if (bufferSize <= 0) {
+ throw new IllegalArgumentException("Buffer size must be positive:
" + bufferSize);
+ }
+
if (input1 == input2) {
return true;
}
if (input1 == null ^ input2 == null) {
return false;
}
- final BufferedReader bufferedInput1 = toBufferedReader(input1);
- final BufferedReader bufferedInput2 = toBufferedReader(input2);
- int ch = bufferedInput1.read();
- while (EOF != ch) {
- final int ch2 = bufferedInput2.read();
- if (ch != ch2) {
+ int input1NumCharsRead = 0;
+ int input2NumCharsRead = 0;
+ final char[] input1Buffer = new char[bufferSize];
+ final char[] input2Buffer = new char[bufferSize];
+ do {
+ input1NumCharsRead = fillBuffer(input1, input1Buffer);
+ input2NumCharsRead = fillBuffer(input2, input2Buffer);
+
+ if (input2NumCharsRead != input1NumCharsRead ||
!Arrays.equals(input1Buffer, input2Buffer)) {
return false;
}
- ch = bufferedInput1.read();
- }
+ } while (input1NumCharsRead == bufferSize && input2NumCharsRead ==
bufferSize);
+
+ return input1.read() == EOF && input2.read() == EOF;
+ }
+
+ /**
+ * This method fills the provided byte array buffer from the provided
<code>Reader</code>. When this method
+ * returns the buffer will either be full or the InputStream will be fully
consumed.
+ *
+ * @param reader the Reader from which to read
+ * @param buffer the buffer to fill
+ * @return the number of chars placed in the buffer. If this is equal to
<code>buffer.length</code> then the
+ * buffer was completely filled. If it is less than
<code>buffer.length</code>, then the Reader has been
+ * fully consumed.
+ * @throws IOException if an I/O error occurs.
+ */
+ private static int fillBuffer(final Reader reader, final char[] buffer)
throws IOException {
+ int totalBytesRead = 0;
+ int bytesRead = 0;
+ do {
+ totalBytesRead += bytesRead;
+ bytesRead = reader.read(buffer, totalBytesRead, buffer.length -
totalBytesRead);
+ } while (bytesRead != -1 && totalBytesRead < buffer.length);
Review comment:
Magic number; use EOF.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services