Skip to content

Commit a2cf546

Browse files
committed
IO-275 FileUtils.contentEquals/IOUtils.contentEquals - Add option to ignore "line endings"
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/io/trunk@1200693 13f79535-47bb-0310-9956-ffa450edef68
1 parent 33e9a89 commit a2cf546

8 files changed

Lines changed: 203 additions & 0 deletions

File tree

src/changes/changes.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ The <action> type attribute can be add,update,fix,remove.
3939
</properties>
4040

4141
<body>
42+
<release version="2.1.1" date="TBA">
43+
<action dev="sebb" type="add" issue="IO-275" due-to="CJ Aspromgos">
44+
FileUtils.contentEquals and IOUtils.contentEquals - Add option to ignore "line endings"
45+
Added contentEqualsIgnoreEOL methods to both classes
46+
</action>
47+
</release>
4248
<!-- The 2.1 release date is the date RC is cut -->
4349
<release version="2.1" date="2011-Sep-28">
4450
<action dev="ggregory" type="add" issue="IO-285" due-to="ggregory">

src/main/java/org/apache/commons/io/FileUtils.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import java.io.FileOutputStream;
2424
import java.io.IOException;
2525
import java.io.InputStream;
26+
import java.io.InputStreamReader;
2627
import java.io.OutputStream;
28+
import java.io.Reader;
2729
import java.math.BigInteger;
2830
import java.net.URL;
2931
import java.net.URLConnection;
@@ -620,6 +622,63 @@ public static boolean contentEquals(File file1, File file2) throws IOException {
620622
}
621623
}
622624

625+
//-----------------------------------------------------------------------
626+
/**
627+
* Compares the contents of two files to determine if they are equal or not.
628+
* <p>
629+
* This method checks to see if the two files point to the same file,
630+
* before resorting to line-by-line comparison of the contents.
631+
* <p>
632+
*
633+
* @param file1 the first file
634+
* @param file2 the second file
635+
* @param charsetName the character encoding to be used.
636+
* May be null, in which case the platform default is used
637+
* @return true if the content of the files are equal or neither exists,
638+
* false otherwise
639+
* @throws IOException in case of an I/O error
640+
* @since 2.1.1
641+
* @see IOUtils#contentEqualsIgnoreEOL(Reader, Reader)
642+
*/
643+
public static boolean contentEqualsIgnoreEOL(File file1, File file2, String charsetName) throws IOException {
644+
boolean file1Exists = file1.exists();
645+
if (file1Exists != file2.exists()) {
646+
return false;
647+
}
648+
649+
if (!file1Exists) {
650+
// two not existing files are equal
651+
return true;
652+
}
653+
654+
if (file1.isDirectory() || file2.isDirectory()) {
655+
// don't want to compare directory contents
656+
throw new IOException("Can't compare directories, only files");
657+
}
658+
659+
if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) {
660+
// same file
661+
return true;
662+
}
663+
664+
Reader input1 = null;
665+
Reader input2 = null;
666+
try {
667+
if (charsetName == null) {
668+
input1 = new InputStreamReader(new FileInputStream(file1));
669+
input2 = new InputStreamReader(new FileInputStream(file2));
670+
} else {
671+
input1 = new InputStreamReader(new FileInputStream(file1), charsetName);
672+
input2 = new InputStreamReader(new FileInputStream(file2), charsetName);
673+
}
674+
return IOUtils.contentEqualsIgnoreEOL(input1, input2);
675+
676+
} finally {
677+
IOUtils.closeQuietly(input1);
678+
IOUtils.closeQuietly(input2);
679+
}
680+
}
681+
623682
//-----------------------------------------------------------------------
624683
/**
625684
* Convert from a <code>URL</code> to a <code>File</code>.

src/main/java/org/apache/commons/io/IOUtils.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,44 @@ public static boolean contentEquals(Reader input1, Reader input2)
16281628
return (ch2 == -1);
16291629
}
16301630

1631+
/**
1632+
* Compare the contents of two Readers to determine if they are equal or
1633+
* not, ignoring EOL characters.
1634+
* <p>
1635+
* This method buffers the input internally using
1636+
* <code>BufferedReader</code> if they are not already buffered.
1637+
*
1638+
* @param input1 the first reader
1639+
* @param input2 the second reader
1640+
* @return true if the content of the readers are equal (ignoring EOL differences), false otherwise
1641+
* @throws NullPointerException if either input is null
1642+
* @throws IOException if an I/O error occurs
1643+
* @since Commons IO 2.1.1
1644+
*/
1645+
public static boolean contentEqualsIgnoreEOL(Reader input1, Reader input2)
1646+
throws IOException {
1647+
BufferedReader br1;
1648+
if (input1 instanceof BufferedReader) {
1649+
br1 = (BufferedReader) input1;
1650+
} else {
1651+
br1 = new BufferedReader(input1);
1652+
}
1653+
BufferedReader br2;
1654+
if (input2 instanceof BufferedReader) {
1655+
br2 = (BufferedReader) input2;
1656+
} else {
1657+
br2 = new BufferedReader(input2);
1658+
}
1659+
1660+
String line1 = br1.readLine();
1661+
String line2 = br2.readLine();
1662+
while (line1 != null && line2 != null && line1.equals(line2)) {
1663+
line1 = br1.readLine();
1664+
line2 = br2.readLine();
1665+
}
1666+
return line1 == null ? (line2 == null ? true : false) : line1.equals(line2);
1667+
}
1668+
16311669
/**
16321670
* Skip bytes from an input byte stream.
16331671
* This implementation guarantees that it will read as many bytes

src/test/java/org/apache/commons/io/FileUtilsTestCase.java

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,75 @@ public void testContentEquals() throws Exception {
539539
assertEquals(true, FileUtils.contentEquals(file, file2));
540540
}
541541

542+
public void testContentEqualsIgnoreEOL() throws Exception {
543+
// Non-existent files
544+
File file1 = new File(getTestDirectory(), getName());
545+
File file2 = new File(getTestDirectory(), getName() + "2");
546+
// both don't exist
547+
assertTrue(FileUtils.contentEqualsIgnoreEOL(file1, file1, null));
548+
assertTrue(FileUtils.contentEqualsIgnoreEOL(file1, file2, null));
549+
assertTrue(FileUtils.contentEqualsIgnoreEOL(file2, file2, null));
550+
assertTrue(FileUtils.contentEqualsIgnoreEOL(file2, file1, null));
551+
552+
// Directories
553+
try {
554+
FileUtils.contentEqualsIgnoreEOL(getTestDirectory(), getTestDirectory(), null);
555+
fail("Comparing directories should fail with an IOException");
556+
} catch (IOException ioe) {
557+
//expected
558+
}
559+
560+
// Different files
561+
File tfile1 = new File(getTestDirectory(), getName() + ".txt1");
562+
tfile1.deleteOnExit();
563+
FileUtils.write(tfile1,"123\r");
564+
565+
File tfile2 = new File(getTestDirectory(), getName() + ".txt2");
566+
tfile1.deleteOnExit();
567+
FileUtils.write(tfile2,"123\n");
568+
569+
File tfile3 = new File(getTestDirectory(), getName() + ".collection");
570+
tfile3.deleteOnExit();
571+
FileUtils.write(tfile3,"123\r\n2");
572+
573+
assertTrue(FileUtils.contentEqualsIgnoreEOL(tfile1, tfile1, null));
574+
assertTrue(FileUtils.contentEqualsIgnoreEOL(tfile2, tfile2, null));
575+
assertTrue(FileUtils.contentEqualsIgnoreEOL(tfile3, tfile3, null));
576+
577+
assertTrue(FileUtils.contentEqualsIgnoreEOL(tfile1, tfile2, null));
578+
assertFalse(FileUtils.contentEqualsIgnoreEOL(tfile1, tfile3, null));
579+
assertFalse(FileUtils.contentEqualsIgnoreEOL(tfile2, tfile3, null));
580+
581+
URL urlCR = getClass().getResource("FileUtilsTestDataCR.dat");
582+
assertNotNull(urlCR);
583+
File cr = new File(urlCR.getPath());
584+
assertTrue(cr.exists());
585+
586+
URL urlCRLF = getClass().getResource("FileUtilsTestDataCRLF.dat");
587+
assertNotNull(urlCRLF);
588+
File crlf = new File(urlCRLF.getPath());
589+
assertTrue(crlf.exists());
590+
591+
URL urlLF = getClass().getResource("FileUtilsTestDataLF.dat");
592+
assertNotNull(urlLF);
593+
File lf = new File(urlLF.getPath());
594+
assertTrue(lf.exists());
595+
596+
assertTrue(FileUtils.contentEqualsIgnoreEOL(cr, cr, null));
597+
assertTrue(FileUtils.contentEqualsIgnoreEOL(crlf, crlf, null));
598+
assertTrue(FileUtils.contentEqualsIgnoreEOL(lf, lf, null));
599+
600+
assertTrue(FileUtils.contentEqualsIgnoreEOL(cr, crlf, null));
601+
assertTrue(FileUtils.contentEqualsIgnoreEOL(cr, lf, null));
602+
assertTrue(FileUtils.contentEqualsIgnoreEOL(crlf, lf, null));
603+
604+
// Equal files
605+
file1.createNewFile();
606+
file2.createNewFile();
607+
assertTrue(FileUtils.contentEqualsIgnoreEOL(file1, file1, null));
608+
assertTrue(FileUtils.contentEqualsIgnoreEOL(file1, file2, null));
609+
}
610+
542611
// copyURLToFile
543612

544613
public void testCopyURLToFile() throws Exception {

src/test/java/org/apache/commons/io/IOUtilsTestCase.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,4 +663,28 @@ public void testURLToStringUsAciiEncoding()
663663
testURLToString("US-ASCII");
664664
}
665665

666+
public void testcontentEqualsIgnoreEOL() throws Exception {
667+
Reader r1;
668+
Reader r2;
669+
670+
r1 = new CharArrayReader("".toCharArray());
671+
r2 = new CharArrayReader("".toCharArray());
672+
assertTrue(IOUtils.contentEqualsIgnoreEOL(r1, r2));
673+
674+
r1 = new CharArrayReader("1".toCharArray());
675+
r2 = new CharArrayReader("1".toCharArray());
676+
assertTrue(IOUtils.contentEqualsIgnoreEOL(r1, r2));
677+
678+
r1 = new CharArrayReader("1".toCharArray());
679+
r2 = new CharArrayReader("2".toCharArray());
680+
assertFalse(IOUtils.contentEqualsIgnoreEOL(r1, r2));
681+
682+
r1 = new CharArrayReader("123\rabc".toCharArray());
683+
r2 = new CharArrayReader("123\nabc".toCharArray());
684+
assertTrue(IOUtils.contentEqualsIgnoreEOL(r1, r2));
685+
686+
r1 = new CharArrayReader("321".toCharArray());
687+
r2 = new CharArrayReader("321\r\n".toCharArray());
688+
assertTrue(IOUtils.contentEqualsIgnoreEOL(r1, r2));
689+
}
666690
}

src/test/resources/org/apache/commons/io/FileUtilsTestDataCR.dat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
123
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
1
2+
2
3+
3
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
1
2+
2
3+
3

0 commit comments

Comments
 (0)