7070import java .util .stream .Collector ;
7171import java .util .stream .Collectors ;
7272import java .util .stream .Stream ;
73+ import java .util .stream .StreamSupport ;
7374
7475import org .apache .commons .io .Charsets ;
7576import 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