Last active
December 3, 2018 20:30
-
-
Save nddipiazza/16cb2a0d23ee60a07121893c26065de4 to your computer and use it in GitHub Desktop.
diff two text files line-by-line in java without loading entire file in memory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import com.google.common.collect.Sets; | |
| import org.apache.commons.io.FileUtils; | |
| import org.apache.commons.io.LineIterator; | |
| import java.io.File; | |
| import java.io.IOException; | |
| import java.util.HashSet; | |
| import java.util.Set; | |
| public class DiffTextFilesUtil { | |
| static public int CHUNK_SIZE = 100000; | |
| static public class DiffResult { | |
| public Set<String> addedVals = new HashSet<>(); | |
| public Set<String> removedVals = new HashSet<>(); | |
| } | |
| /** | |
| * Gets diff result of two sorted files with each other. | |
| * @param lhs left hand file - sort this using com.google.code.externalsortinginjava:externalsortinginjava:0.2.5 | |
| * @param rhs right hand file - sort this using com.google.code.externalsortinginjava:externalsortinginjava:0.2.5 | |
| * @return DiffResult.addedVals were added from lhs to rhs. DiffResult.removedVals were removed from lhs to rhs. | |
| * @throws IOException | |
| */ | |
| public static DiffResult diff(File lhs, File rhs) throws IOException { | |
| DiffResult diffResult = new DiffResult(); | |
| LineIterator lhsIter = FileUtils.lineIterator(lhs); | |
| LineIterator rhsIter = FileUtils.lineIterator(rhs); | |
| String lhsTop = null; | |
| String rhsTop = null; | |
| while (lhsIter.hasNext()) { | |
| int ct = CHUNK_SIZE; | |
| Set<String> setLhs = Sets.newHashSet(); | |
| Set<String> setRhs = Sets.newHashSet(); | |
| while (lhsIter.hasNext() && --ct > 0) { | |
| lhsTop = lhsIter.nextLine(); | |
| setLhs.add(lhsTop); | |
| } | |
| while (rhsIter.hasNext()) { | |
| if (rhsTop != null && rhsTop.compareTo(lhsTop) > 0) { | |
| break; | |
| } else if (rhsTop != null && rhsTop.compareTo(lhsTop) == 0) { | |
| setRhs.add(rhsTop); | |
| rhsTop = null; | |
| break; | |
| } else if (rhsTop != null) { | |
| setRhs.add(rhsTop); | |
| } | |
| rhsTop = rhsIter.next(); | |
| } | |
| if (rhsTop != null) { | |
| setRhs.add(rhsTop); | |
| } | |
| Sets.difference(setLhs, setRhs).copyInto(diffResult.removedVals); | |
| Sets.difference(setRhs, setLhs).copyInto(diffResult.addedVals); | |
| } | |
| return diffResult; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import com.google.common.collect.Lists; | |
| import org.apache.commons.io.FileUtils; | |
| import org.junit.Assert; | |
| import org.junit.Test; | |
| import java.io.File; | |
| import java.util.List; | |
| public class DiffTextFilesUtilTest { | |
| @Test | |
| public void testDiffTextFiles() throws Exception { | |
| List<String> strsLhs = Lists.newArrayList(); | |
| for (int i=0; i<20000; ++i) { | |
| strsLhs.add(String.format("val%06d", i)); | |
| } | |
| List<String> strsRhs = Lists.newArrayList(); | |
| for (int i=0; i<20000; ++i) { | |
| if (i % 25 == 0) { | |
| strsRhs.add(String.format("val%06dxx", i)); | |
| } else if (i % 33 != 0) { | |
| strsRhs.add(String.format("val%06d", i)); | |
| } | |
| } | |
| File tmp1 = File.createTempFile("tempfile-lhs", ".csv"); | |
| File tmp2 = File.createTempFile("tempfile-rhs", ".csv"); | |
| FileUtils.writeLines(tmp1, strsLhs); | |
| FileUtils.writeLines(tmp2, strsRhs); | |
| DiffTextFilesUtil.DiffResult diffResult = DiffTextFilesUtil.diff( | |
| tmp1, | |
| tmp2); | |
| Assert.assertEquals(diffResult.addedVals.size(), 800); | |
| for (String addedVal : diffResult.addedVals) { | |
| Assert.assertTrue(addedVal.contains("xx")); | |
| addedVal = addedVal.replace("val", ""); | |
| addedVal = addedVal.replace("xx", ""); | |
| int remValInt = Integer.parseInt(addedVal); | |
| Assert.assertEquals(remValInt + " % 25 == " + remValInt % 25 + " should be 0 ", remValInt % 25, 0); | |
| } | |
| Assert.assertEquals(diffResult.removedVals.size(), 1382); | |
| for (String remVal : diffResult.removedVals) { | |
| remVal = remVal.replace("val", ""); | |
| int remValInt = Integer.parseInt(remVal); | |
| if (remValInt % 25 != 0) { | |
| Assert.assertEquals(remVal + " % 33 == " + remValInt % 33 + " should be 0 ", remValInt % 33, 0); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment