Skip to content

Instantly share code, notes, and snippets.

@nddipiazza
Last active December 3, 2018 20:30
Show Gist options
  • Select an option

  • Save nddipiazza/16cb2a0d23ee60a07121893c26065de4 to your computer and use it in GitHub Desktop.

Select an option

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
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;
}
}
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