|
52 | 52 |
|
53 | 53 | import org.apache.commons.io.function.IOConsumer; |
54 | 54 | import org.apache.commons.io.input.buffer.LineEndUnifiedBufferedReader; |
55 | | -import org.apache.commons.io.input.buffer.UnsyncBufferedInputStream; |
56 | | -import org.apache.commons.io.input.buffer.UnsyncBufferedReader; |
57 | 55 | import org.apache.commons.io.output.AppendableWriter; |
58 | 56 | import org.apache.commons.io.output.ByteArrayOutputStream; |
59 | 57 | import org.apache.commons.io.output.StringBuilderWriter; |
@@ -215,41 +213,6 @@ public static BufferedInputStream buffer(final InputStream inputStream, final in |
215 | 213 | (BufferedInputStream) inputStream : new BufferedInputStream(inputStream, size); |
216 | 214 | } |
217 | 215 |
|
218 | | - /** |
219 | | - * Returns the given InputStream if it is already a {@link UnsyncBufferedInputStream}, otherwise creates a |
220 | | - * UnsyncBufferedInputStream from the given InputStream. |
221 | | - * |
222 | | - * @param inputStream the InputStream to wrap or return (not null) |
223 | | - * @return the given InputStream or a new {@link UnsyncBufferedInputStream} for the given InputStream |
224 | | - * @throws NullPointerException if the input parameter is null |
225 | | - * @since 2.5 |
226 | | - */ |
227 | | - private static UnsyncBufferedInputStream unsyncBuffer(final InputStream inputStream) { |
228 | | - // reject null early on rather than waiting for IO operation to fail |
229 | | - // not checked by BufferedInputStream |
230 | | - Objects.requireNonNull(inputStream, "inputStream"); |
231 | | - return inputStream instanceof UnsyncBufferedInputStream ? |
232 | | - (UnsyncBufferedInputStream) inputStream : new UnsyncBufferedInputStream(inputStream); |
233 | | - } |
234 | | - |
235 | | - /** |
236 | | - * Returns the given InputStream if it is already a {@link UnsyncBufferedInputStream}, otherwise creates a |
237 | | - * UnsyncBufferedInputStream from the given InputStream. |
238 | | - * |
239 | | - * @param inputStream the InputStream to wrap or return (not null) |
240 | | - * @param size the buffer size, if a new UnsyncBufferedInputStream is created. |
241 | | - * @return the given InputStream or a new {@link UnsyncBufferedInputStream} for the given InputStream |
242 | | - * @throws UnsyncBufferedInputStream if the input parameter is null |
243 | | - * @since 2.5 |
244 | | - */ |
245 | | - private static UnsyncBufferedInputStream unsyncBuffer(final InputStream inputStream, final int size) { |
246 | | - // reject null early on rather than waiting for IO operation to fail |
247 | | - // not checked by BufferedInputStream |
248 | | - Objects.requireNonNull(inputStream, "inputStream"); |
249 | | - return inputStream instanceof UnsyncBufferedInputStream ? |
250 | | - (UnsyncBufferedInputStream) inputStream : new UnsyncBufferedInputStream(inputStream, size); |
251 | | - } |
252 | | - |
253 | 216 | /** |
254 | 217 | * Returns the given OutputStream if it is already a {@link BufferedOutputStream}, otherwise creates a |
255 | 218 | * BufferedOutputStream from the given OutputStream. |
@@ -312,33 +275,6 @@ public static BufferedReader buffer(final Reader reader, final int size) { |
312 | 275 | return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader, size); |
313 | 276 | } |
314 | 277 |
|
315 | | - /** |
316 | | - * Returns the given reader if it is already a {@link UnsyncBufferedReader}, otherwise creates a UnsyncBufferedReader from |
317 | | - * the given reader. |
318 | | - * |
319 | | - * @param reader the reader to wrap or return (not null) |
320 | | - * @return the given reader or a new {@link UnsyncBufferedReader} for the given reader |
321 | | - * @throws NullPointerException if the input parameter is null |
322 | | - * @since 2.5 |
323 | | - */ |
324 | | - private static UnsyncBufferedReader unsyncBuffer(final Reader reader) { |
325 | | - return reader instanceof UnsyncBufferedReader ? (UnsyncBufferedReader) reader : new UnsyncBufferedReader(reader); |
326 | | - } |
327 | | - |
328 | | - /** |
329 | | - * Returns the given reader if it is already a {@link UnsyncBufferedReader}, otherwise creates a UnsyncBufferedReader from the |
330 | | - * given reader. |
331 | | - * |
332 | | - * @param reader the reader to wrap or return (not null) |
333 | | - * @param size the buffer size, if a new UnsyncBufferedReader is created. |
334 | | - * @return the given reader or a new {@link UnsyncBufferedReader} for the given reader |
335 | | - * @throws NullPointerException if the input parameter is null |
336 | | - * @since 2.5 |
337 | | - */ |
338 | | - private static UnsyncBufferedReader unsyncBuffer(final Reader reader, final int size) { |
339 | | - return reader instanceof UnsyncBufferedReader ? (UnsyncBufferedReader) reader : new UnsyncBufferedReader(reader, size); |
340 | | - } |
341 | | - |
342 | 278 | /** |
343 | 279 | * Returns the given Writer if it is already a {@link BufferedWriter}, otherwise creates a BufferedWriter from the |
344 | 280 | * given Writer. |
@@ -773,23 +709,48 @@ public static void closeQuietly(final Writer output) { |
773 | 709 | @SuppressWarnings("resource") |
774 | 710 | public static boolean contentEquals(final InputStream input1, final InputStream input2) |
775 | 711 | throws IOException { |
| 712 | + // see comments in public static boolean contentEquals(final Reader input1, final Reader input2) |
| 713 | + // this function is mirror to it. |
776 | 714 | if (input1 == input2) { |
777 | 715 | return true; |
778 | 716 | } |
779 | 717 | if (input1 == null ^ input2 == null) { |
780 | 718 | return false; |
781 | 719 | } |
782 | | - final UnsyncBufferedInputStream bufferedInput1 = unsyncBuffer(input1); |
783 | | - final UnsyncBufferedInputStream bufferedInput2 = unsyncBuffer(input2); |
784 | | - int ch = bufferedInput1.read(); |
785 | | - while (EOF != ch) { |
786 | | - final int ch2 = bufferedInput2.read(); |
787 | | - if (ch != ch2) { |
788 | | - return false; |
| 720 | + |
| 721 | + byte[] byteArray1 = new byte[DEFAULT_BUFFER_SIZE]; |
| 722 | + byte[] byteArray2 = new byte[DEFAULT_BUFFER_SIZE]; |
| 723 | + int nowPos1; |
| 724 | + int nowPos2; |
| 725 | + int nowRead1; |
| 726 | + int nowRead2; |
| 727 | + while (true) { |
| 728 | + nowPos1 = 0; |
| 729 | + nowPos2 = 0; |
| 730 | + for (int nowCheck = 0; nowCheck < DEFAULT_BUFFER_SIZE; nowCheck++) { |
| 731 | + if (nowPos1 == nowCheck) { |
| 732 | + do { |
| 733 | + nowRead1 = input1.read(byteArray1, nowPos1, DEFAULT_BUFFER_SIZE - nowPos1); |
| 734 | + } while (nowRead1 == 0); |
| 735 | + if (nowRead1 == EOF) { |
| 736 | + return nowPos2 == nowCheck && input2.read() == EOF; |
| 737 | + } |
| 738 | + nowPos1 += nowRead1; |
| 739 | + } |
| 740 | + if (nowPos2 == nowCheck) { |
| 741 | + do { |
| 742 | + nowRead2 = input2.read(byteArray2, nowPos2, DEFAULT_BUFFER_SIZE - nowPos2); |
| 743 | + } while (nowRead2 == 0); |
| 744 | + if (nowRead2 == EOF) { |
| 745 | + return nowPos1 == nowCheck && input1.read() == EOF; |
| 746 | + } |
| 747 | + nowPos2 += nowRead2; |
| 748 | + } |
| 749 | + if (byteArray1[nowCheck] != byteArray2[nowCheck]) { |
| 750 | + return false; |
| 751 | + } |
789 | 752 | } |
790 | | - ch = bufferedInput1.read(); |
791 | 753 | } |
792 | | - return bufferedInput2.read() == EOF; |
793 | 754 | } |
794 | 755 |
|
795 | 756 | /** |
@@ -817,19 +778,79 @@ public static boolean contentEquals(final Reader input1, final Reader input2) |
817 | 778 | if (input1 == null ^ input2 == null) { |
818 | 779 | return false; |
819 | 780 | } |
820 | | - final UnsyncBufferedReader bufferedInput1 = unsyncBuffer(input1); |
821 | | - final UnsyncBufferedReader bufferedInput2 = unsyncBuffer(input2); |
822 | 781 |
|
823 | | - int ch = bufferedInput1.read(); |
824 | | - while (EOF != ch) { |
825 | | - final int ch2 = bufferedInput2.read(); |
826 | | - if (ch != ch2) { |
827 | | - return false; |
| 782 | + // char buffer array for input1 |
| 783 | + char[] charArray1 = new char[DEFAULT_BUFFER_SIZE]; |
| 784 | + // char buffer array for input2 |
| 785 | + char[] charArray2 = new char[DEFAULT_BUFFER_SIZE]; |
| 786 | + |
| 787 | + // the current last-index of chars read to charArray1 from input1 |
| 788 | + int nowPos1; |
| 789 | + // the current last-index of chars read to charArray2 from input2 |
| 790 | + int nowPos2; |
| 791 | + // the chars read this time. |
| 792 | + int nowRead; |
| 793 | + while (true) { |
| 794 | + nowPos1 = 0; |
| 795 | + nowPos2 = 0; |
| 796 | + /* |
| 797 | + * For better performance, this loop is special designed. |
| 798 | + * Since input1 and input2's content must be equal to return true, |
| 799 | + * we share the index used in the two char buffers, |
| 800 | + * by simply make it from 0 to DEFAULT_BUFFER_SIZE, means 8192. |
| 801 | + * Every time it read, it read as long as possible, both limited by the input reader itself, |
| 802 | + * and the remaining length of this array. |
| 803 | + * The performance of the following loop can be proved simply. |
| 804 | + * 1. If the reader can read only several chars during one read() call: |
| 805 | + * then we only invert it every 8192 times, thus it will not be time costing. |
| 806 | + * 2. If the reader can read many chars during one read() call: |
| 807 | + * then it will be filled fast, and also will not be time costing. |
| 808 | + */ |
| 809 | + for (int nowCheck = 0; nowCheck < DEFAULT_BUFFER_SIZE; nowCheck++) { |
| 810 | + if (nowPos1 == nowCheck) { |
| 811 | + // if nowPos1 == nowCheck, |
| 812 | + // then means charArray1[nowCheck] |
| 813 | + // is empty now, thus we need to invoke read on input1 first. |
| 814 | + do { |
| 815 | + // read as many chars as possible, using the remaining spaces of charArray1. |
| 816 | + nowRead = input1.read(charArray1, nowPos1, DEFAULT_BUFFER_SIZE - nowPos1); |
| 817 | + } while (nowRead == 0); |
| 818 | + if (nowRead == EOF) { |
| 819 | + // if input1 ends, then we check if input2 ends too. |
| 820 | + // if nowPos2 == nowCheck && input2.read() == EOF, |
| 821 | + // we think input2 have no more chars, |
| 822 | + // and cannot read more either, |
| 823 | + // thus return true. |
| 824 | + // otherwise return false. |
| 825 | + return nowPos2 == nowCheck && input2.read() == EOF; |
| 826 | + } |
| 827 | + nowPos1 += nowRead; |
| 828 | + } |
| 829 | + if (nowPos2 == nowCheck) { |
| 830 | + // if nowPos1 == nowCheck, |
| 831 | + // then means charArray1[nowCheck] |
| 832 | + // is empty now, thus we need to invoke read on input1 first. |
| 833 | + do { |
| 834 | + // read as many chars as possible, using the remaining spaces of charArray2. |
| 835 | + nowRead = input2.read(charArray2, nowPos2, DEFAULT_BUFFER_SIZE - nowPos2); |
| 836 | + } while (nowRead == 0); |
| 837 | + if (nowRead == EOF) { |
| 838 | + // if input2 ends, then we check if input1 ends too. |
| 839 | + // if nowPos1 == nowCheck && input1.read() == EOF, |
| 840 | + // we think input1 have no more chars, |
| 841 | + // and cannot read more either, |
| 842 | + // thus return true. |
| 843 | + // otherwise return false. |
| 844 | + return nowPos1 == nowCheck && input1.read() == EOF; |
| 845 | + } |
| 846 | + nowPos2 += nowRead; |
| 847 | + } |
| 848 | + // now we have |
| 849 | + if (charArray1[nowCheck] != charArray2[nowCheck]) { |
| 850 | + return false; |
| 851 | + } |
828 | 852 | } |
829 | | - ch = bufferedInput1.read(); |
830 | 853 | } |
831 | | - |
832 | | - return bufferedInput2.read() == EOF; |
833 | 854 | } |
834 | 855 |
|
835 | 856 | /** |
|
0 commit comments