@@ -303,6 +303,44 @@ private static int compareLastModifiedTimeTo(final Path file, final FileTime fil
303303 return getLastModifiedTime (file , options ).compareTo (fileTime );
304304 }
305305
306+ /**
307+ * 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
308+ * subdirectories.
309+ * <p>
310+ * For example, to compare two ZIP files:
311+ * </p>
312+ *
313+ * <pre>
314+ * final Path zipPath1 = Paths.get("file1.zip");
315+ * final Path zipPath2 = Paths.get("file2.zip");
316+ * try (FileSystem fileSystem1 = FileSystems.newFileSystem(zipPath1, null); FileSystem fileSystem2 = FileSystems.newFileSystem(zipPath2, null)) {
317+ * assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
318+ * }
319+ * </pre>
320+ *
321+ * @param fileSystem1 The first FileSystem.
322+ * @param fileSystem2 The second FileSystem.
323+ * @return Whether the two FileSystem contain the same files while considering file contents.
324+ * @throws IOException if an I/O error is thrown by a visitor method.
325+ * @since 2.19.0
326+ */
327+ public static boolean contentEquals (final FileSystem fileSystem1 , final FileSystem fileSystem2 ) throws IOException {
328+ if (Objects .equals (fileSystem1 , fileSystem2 )) {
329+ return true ;
330+ }
331+ final List <Path > sortedList1 = toSortedList (fileSystem1 .getRootDirectories ());
332+ final List <Path > sortedList2 = toSortedList (fileSystem2 .getRootDirectories ());
333+ if (sortedList1 .size () != sortedList2 .size ()) {
334+ return false ;
335+ }
336+ for (int i = 0 ; i < sortedList1 .size (); i ++) {
337+ if (!directoryAndFileContentEquals (sortedList1 .get (i ), sortedList2 .get (i ))) {
338+ return false ;
339+ }
340+ }
341+ return true ;
342+ }
343+
306344 /**
307345 * Copies the InputStream from the supplier with {@link Files#copy(InputStream, Path, CopyOption...)}.
308346 *
@@ -362,12 +400,7 @@ public static Path copyFile(final URL sourceFile, final Path targetFile, final C
362400 public static Path copyFileToDirectory (final Path sourceFile , final Path targetDirectory , final CopyOption ... copyOptions ) throws IOException {
363401 // Path.resolve() naturally won't work across FileSystem unless we convert to a String
364402 final Path sourceFileName = Objects .requireNonNull (sourceFile .getFileName (), "source file name" );
365- final Path targetFile ;
366- if (isSameFileSystem (sourceFileName , targetDirectory )) {
367- targetFile = targetDirectory .resolve (sourceFileName );
368- } else {
369- targetFile = targetDirectory .resolve (sourceFileName .toString ());
370- }
403+ final Path targetFile = resolve (targetDirectory , sourceFileName );
371404 return Files .copy (sourceFile , targetFile , copyOptions );
372405 }
373406
@@ -667,54 +700,6 @@ public static boolean directoryAndFileContentEquals(final Path path1, final Path
667700 return directoryAndFileContentEquals (path1 , path2 , EMPTY_LINK_OPTION_ARRAY , EMPTY_OPEN_OPTION_ARRAY , EMPTY_FILE_VISIT_OPTION_ARRAY );
668701 }
669702
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-
718703 /**
719704 * 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
720705 * subdirectories.
@@ -1572,6 +1557,18 @@ private static Path requireExists(final Path file, final String fileParamName, f
15721557 return file ;
15731558 }
15741559
1560+ static Path resolve (final Path targetDirectory , final Path otherPath ) {
1561+ final FileSystem fileSystemTarget = targetDirectory .getFileSystem ();
1562+ final FileSystem fileSystemSource = otherPath .getFileSystem ();
1563+ if (fileSystemTarget == fileSystemSource ) {
1564+ return targetDirectory .resolve (otherPath );
1565+ }
1566+ final String separatorSource = fileSystemSource .getSeparator ();
1567+ final String separatorTarget = fileSystemTarget .getSeparator ();
1568+ final String otherString = otherPath .toString ();
1569+ return targetDirectory .resolve (Objects .equals (separatorSource , separatorTarget ) ? otherString : otherString .replace (separatorSource , separatorTarget ));
1570+ }
1571+
15751572 private static boolean setDosReadOnly (final Path path , final boolean readOnly , final LinkOption ... linkOptions ) throws IOException {
15761573 final DosFileAttributeView dosFileAttributeView = getDosFileAttributeView (path , linkOptions );
15771574 if (dosFileAttributeView != null ) {
@@ -1800,6 +1797,16 @@ static Set<FileVisitOption> toFileVisitOptionSet(final FileVisitOption... fileVi
18001797 return fileVisitOptions == null ? EnumSet .noneOf (FileVisitOption .class ) : Stream .of (fileVisitOptions ).collect (Collectors .toSet ());
18011798 }
18021799
1800+ private static <T > List <T > toList (final Iterable <T > iterable ) {
1801+ return StreamSupport .stream (iterable .spliterator (), false ).collect (Collectors .toList ());
1802+ }
1803+
1804+ private static List <Path > toSortedList (final Iterable <Path > rootDirectories ) {
1805+ final List <Path > list = toList (rootDirectories );
1806+ Collections .sort (list );
1807+ return list ;
1808+ }
1809+
18031810 /**
18041811 * Implements behavior similar to the Unix "touch" utility. Creates a new file with size 0, or, if the file exists, just updates the file's modified time.
18051812 * this method creates parent directories if they do not exist.
0 commit comments