Skip to content

Commit 4e45c01

Browse files
committed
Add PathUtils.contentEquals(FileSystem, FileSystem)
1 parent 4efa8cf commit 4e45c01

File tree

3 files changed

+169
-57
lines changed

3 files changed

+169
-57
lines changed

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ The <action> type attribute can be add,update,fix,remove.
9393
<action dev="ggregory" type="add" issue="IO-872" due-to="Gary Gregory">Add SimplePathVisitor.AbstractBuilder.</action>
9494
<action dev="ggregory" type="add" issue="IO-872" due-to="Gary Gregory">Add CountingPathVisitor.AbstractBuilder and CountingPathVisitor.Builder.</action>
9595
<action dev="ggregory" type="add" issue="IO-872" due-to="Gary Gregory">Add AccumulatorPathVisitor.Builder and builder().</action>
96+
<action dev="ggregory" type="add" due-to="Gary Gregory">Add PathUtils.contentEquals(FileSystem, FileSystem).</action>
9697
<!-- UPDATE -->
9798
<action dev="ggregory" type="update" due-to="Dependabot, Gary Gregory">Bump commons.bytebuddy.version from 1.15.10 to 1.17.5 #710, #715, #720, #734, #735.</action>
9899
<action dev="ggregory" type="update" due-to="Gary Gregory">Bump commons-codec:commons-codec from 1.17.1 to 1.18.0. #717.</action>

src/main/java/org/apache/commons/io/file/PathUtils.java

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import java.util.stream.Collector;
7171
import java.util.stream.Collectors;
7272
import java.util.stream.Stream;
73+
import java.util.stream.StreamSupport;
7374

7475
import org.apache.commons.io.Charsets;
7576
import org.apache.commons.io.FileUtils;
@@ -654,7 +655,7 @@ public static void deleteOnExit(final Path path) {
654655
}
655656

656657
/**
657-
* Compares the file sets of two Paths to determine if they are equal or not while considering file contents. The comparison includes all files in all
658+
* Compares the files of two Paths to determine if they are equal or not while considering file contents. The comparison includes all files in all
658659
* subdirectories.
659660
*
660661
* @param path1 The first directory.
@@ -666,6 +667,54 @@ public static boolean directoryAndFileContentEquals(final Path path1, final Path
666667
return directoryAndFileContentEquals(path1, path2, EMPTY_LINK_OPTION_ARRAY, EMPTY_OPEN_OPTION_ARRAY, EMPTY_FILE_VISIT_OPTION_ARRAY);
667668
}
668669

670+
/**
671+
* Compares the files of two FileSystems to determine if they are equal or not while considering file contents. The comparison includes all files in all
672+
* subdirectories.
673+
* <p>
674+
* For example, to compare two ZIP files:
675+
* </p>
676+
*
677+
* <pre>
678+
* final Path zipPath1 = Paths.get("file1.zip");
679+
* final Path zipPath2 = Paths.get("file2.zip");
680+
* try (FileSystem fileSystem1 = FileSystems.newFileSystem(zipPath1, null); FileSystem fileSystem2 = FileSystems.newFileSystem(zipPath2, null)) {
681+
* assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
682+
* }
683+
* </pre>
684+
*
685+
* @param fileSystem1 The first FileSystem.
686+
* @param fileSystem2 The second FileSystem.
687+
* @return Whether the two FileSystem contain the same files while considering file contents.
688+
* @throws IOException if an I/O error is thrown by a visitor method.
689+
* @since 2.19.0
690+
*/
691+
public static boolean contentEquals(final FileSystem fileSystem1, final FileSystem fileSystem2) throws IOException {
692+
if (Objects.equals(fileSystem1, fileSystem2)) {
693+
return true;
694+
}
695+
final List<Path> sortedList1 = toSortedList(fileSystem1.getRootDirectories());
696+
final List<Path> sortedList2 = toSortedList(fileSystem2.getRootDirectories());
697+
if (sortedList1.size() != sortedList2.size()) {
698+
return false;
699+
}
700+
for (int i = 0; i < sortedList1.size(); i++) {
701+
if (!directoryAndFileContentEquals(sortedList1.get(i), sortedList2.get(i))) {
702+
return false;
703+
}
704+
}
705+
return true;
706+
}
707+
708+
private static List<Path> toSortedList(final Iterable<Path> rootDirectories) {
709+
final List<Path> list = toList(rootDirectories);
710+
list.sort(Comparator.comparing(Function.identity()));
711+
return list;
712+
}
713+
714+
private static <T> List<T> toList(final Iterable<T> iterable) {
715+
return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
716+
}
717+
669718
/**
670719
* Compares the file sets of two Paths to determine if they are equal or not while considering file contents. The comparison includes all files in all
671720
* subdirectories.
@@ -756,8 +805,8 @@ private static boolean exists(final Path path, final LinkOption... options) {
756805
* File content is accessed through {@link Files#newInputStream(Path,OpenOption...)}.
757806
* </p>
758807
*
759-
* @param path1 the first stream.
760-
* @param path2 the second stream.
808+
* @param path1 the first file path.
809+
* @param path2 the second file path.
761810
* @return true if the content of the streams are equal or they both don't exist, false otherwise.
762811
* @throws NullPointerException if either input is null.
763812
* @throws IOException if an I/O error occurs.
@@ -773,8 +822,8 @@ public static boolean fileContentEquals(final Path path1, final Path path2) thro
773822
* File content is accessed through {@link RandomAccessFileMode#create(Path)}.
774823
* </p>
775824
*
776-
* @param path1 the first stream.
777-
* @param path2 the second stream.
825+
* @param path1 the first file path.
826+
* @param path2 the second file path.
778827
* @param linkOptions options specifying how files are followed.
779828
* @param openOptions ignored.
780829
* @return true if the content of the streams are equal or they both don't exist, false otherwise.
@@ -813,7 +862,7 @@ public static boolean fileContentEquals(final Path path1, final Path path2, fina
813862
// lengths differ, cannot be equal
814863
return false;
815864
}
816-
if (path1.equals(path2)) {
865+
if (isSameFileSystem(path1, path2) && path1.equals(path2)) {
817866
// same file
818867
return true;
819868
}

0 commit comments

Comments
 (0)