@@ -60,78 +60,43 @@ public static boolean contentEquals(final FileChannel channel1, final FileChanne
6060 */
6161 public static boolean contentEquals (final ReadableByteChannel channel1 , final ReadableByteChannel channel2 , final int bufferCapacity ) throws IOException {
6262 // Before making any changes, please test with org.apache.commons.io.jmh.IOUtilsContentEqualsInputStreamsBenchmark
63- if (bufferCapacity <= 0 ) {
64- throw new IllegalArgumentException ();
65- }
6663 // Short-circuit test
6764 if (Objects .equals (channel1 , channel2 )) {
6865 return true ;
6966 }
7067 // Dig in and do the work
7168 final ByteBuffer c1Buffer = ByteBuffer .allocateDirect (bufferCapacity );
7269 final ByteBuffer c2Buffer = ByteBuffer .allocateDirect (bufferCapacity );
73- int c1ReadNum = -1 ;
74- int c2ReadNum = -1 ;
75- boolean c1Read = true ;
76- boolean c2Read = true ;
77- boolean equals = false ;
70+ int c1NumRead = 0 ;
71+ int c2NumRead = 0 ;
72+ boolean c1Read0 = false ;
73+ boolean c2Read0 = false ;
7874 // If a channel is a non-blocking channel, it may return 0 bytes read for any given call.
7975 while (true ) {
80- // don't call compact() in this method to avoid copying
81- if (c1Read ) {
82- c1ReadNum = channel1 .read (c1Buffer );
83- c1Buffer .position (0 );
84- c1Read = c1ReadNum >= 0 ;
76+ if (!c2Read0 ) {
77+ c1NumRead = readToLimit (channel1 , c1Buffer );
78+ c1Buffer .clear ();
79+ c1Read0 = c1NumRead == 0 ;
8580 }
86- if (c2Read ) {
87- c2ReadNum = channel2 . read ( c2Buffer );
88- c2Buffer .position ( 0 );
89- c2Read = c2ReadNum > = 0 ;
81+ if (! c1Read0 ) {
82+ c2NumRead = readToLimit ( channel2 , c2Buffer );
83+ c2Buffer .clear ( );
84+ c2Read0 = c2NumRead = = 0 ;
9085 }
91- if (c1ReadNum == IOUtils .EOF && c2ReadNum == IOUtils .EOF ) {
92- return equals || c1Buffer .equals (c2Buffer );
86+ if (c1NumRead == IOUtils .EOF && c2NumRead == IOUtils .EOF ) {
87+ return c1Buffer .equals (c2Buffer );
9388 }
94- if (c1ReadNum == 0 || c2ReadNum == 0 ) {
89+ if (c1NumRead == 0 || c2NumRead == 0 ) {
90+ // 0 may be returned from a non-blocking channel.
9591 Thread .yield ();
96- }
97- if (c1ReadNum == 0 && c2ReadNum == IOUtils .EOF || c2ReadNum == 0 && c1ReadNum == IOUtils .EOF ) {
9892 continue ;
9993 }
100- if (c1ReadNum != c2ReadNum ) {
101- final int limit = Math .min (c1ReadNum , c2ReadNum );
102- if (limit == IOUtils .EOF ) {
103- return false ;
104- }
105- c1Buffer .limit (limit );
106- c2Buffer .limit (limit );
107- if (!c1Buffer .equals (c2Buffer )) {
108- return false ;
109- }
110- equals = true ;
111- c1Buffer .limit (bufferCapacity );
112- c2Buffer .limit (bufferCapacity );
113- c1Read = c2ReadNum > c1ReadNum ;
114- c2Read = c1ReadNum > c2ReadNum ;
115- if (c1Read ) {
116- c1Buffer .position (0 );
117- } else {
118- c1Buffer .position (limit );
119- c2Buffer .limit (c1Buffer .remaining ());
120- c1ReadNum -= c2ReadNum ;
121- }
122- if (c2Read ) {
123- c2Buffer .position (0 );
124- } else {
125- c2Buffer .position (limit );
126- c1Buffer .limit (c2Buffer .remaining ());
127- c2ReadNum -= c1ReadNum ;
128- }
129- continue ;
94+ if (c1NumRead != c2NumRead ) {
95+ return false ;
13096 }
13197 if (!c1Buffer .equals (c2Buffer )) {
13298 return false ;
13399 }
134- equals = c1Read = c2Read = true ;
135100 }
136101 }
137102
@@ -162,6 +127,36 @@ public static boolean contentEquals(final SeekableByteChannel channel1, final Se
162127 return size1 == 0 && size2 == 0 || contentEquals ((ReadableByteChannel ) channel1 , channel2 , bufferCapacity );
163128 }
164129
130+ /**
131+ * Reads a sequence of bytes from a channel into the given buffer until the buffer reaches its limit or the channel has reaches end-of-stream.
132+ * <p>
133+ * The buffer's limit is not changed.
134+ * </p>
135+ *
136+ * @param channel The source channel.
137+ * @param dst The buffer into which bytes are to be transferred.
138+ * @return The number of bytes read, possibly zero, or {@code-1} if the channel has reached end-of-stream
139+ * @throws IOException If some other I/O error occurs.
140+ * @throws IllegalArgumentException If there is room in the given buffer.
141+ */
142+ private static int readToLimit (final ReadableByteChannel channel , final ByteBuffer dst ) throws IOException {
143+ if (!dst .hasRemaining ()) {
144+ throw new IllegalArgumentException ();
145+ }
146+ int numRead = 0 ;
147+ int totalRead = 0 ;
148+ while (dst .hasRemaining ()) {
149+ if ((totalRead += numRead = channel .read (dst )) == IOUtils .EOF ) {
150+ break ;
151+ }
152+ if (numRead == 0 ) {
153+ // 0 may be returned from a non-blocking channel.
154+ Thread .yield ();
155+ }
156+ }
157+ return totalRead ;
158+ }
159+
165160 private static long size (final SeekableByteChannel channel ) throws IOException {
166161 return channel != null ? channel .size () : 0 ;
167162 }
0 commit comments