How to copy a directory with its attributes/permissions from one location to another?

StackOverflow https://stackoverflow.com/questions/17641706

  •  03-06-2022
  •  | 
  •  

Question

I see a lot of examples that use Files.walkFileTree() to copy a directory and its contents from one location to another, but they fail to take the directory's file attributes and permissions into consideration. Meaning, they just invoke Files.createDirectories() without any attributes or permissions.

How does one copy a directory (and its contents) from one location to another without losing file attributes or permissions, using the Java7 core classes?

Was it helpful?

Solution

Answering my own question:

/**
 * Copies a directory.
 * <p>
 * NOTE: This method is not thread-safe.
 * <p>
 * 
 * @param source
 *            the directory to copy from
 * @param target
 *            the directory to copy into
 * @throws IOException
 *             if an I/O error occurs
 */
private static void copyDirectory(final Path source, final Path target)
        throws IOException {
    Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS),
        Integer.MAX_VALUE, new FileVisitor<Path>() {

            @Override
            public FileVisitResult preVisitDirectory(Path dir,
                    BasicFileAttributes sourceBasic) throws IOException {
                Path targetDir = Files.createDirectories(target
                    .resolve(source.relativize(dir)));
                AclFileAttributeView acl = Files.getFileAttributeView(dir,
                    AclFileAttributeView.class);
                if (acl != null)
                    Files.getFileAttributeView(targetDir,
                        AclFileAttributeView.class).setAcl(acl.getAcl());
                DosFileAttributeView dosAttrs = Files.getFileAttributeView(
                    dir, DosFileAttributeView.class);
                if (dosAttrs != null) {
                    DosFileAttributes sourceDosAttrs = dosAttrs
                        .readAttributes();
                    DosFileAttributeView targetDosAttrs = Files
                        .getFileAttributeView(targetDir,
                            DosFileAttributeView.class);
                    targetDosAttrs.setArchive(sourceDosAttrs.isArchive());
                    targetDosAttrs.setHidden(sourceDosAttrs.isHidden());
                    targetDosAttrs.setReadOnly(sourceDosAttrs.isReadOnly());
                    targetDosAttrs.setSystem(sourceDosAttrs.isSystem());
                }
                FileOwnerAttributeView ownerAttrs = Files
                    .getFileAttributeView(dir, FileOwnerAttributeView.class);
                if (ownerAttrs != null) {
                    FileOwnerAttributeView targetOwner = Files
                        .getFileAttributeView(targetDir,
                            FileOwnerAttributeView.class);
                    targetOwner.setOwner(ownerAttrs.getOwner());
                }
                PosixFileAttributeView posixAttrs = Files
                    .getFileAttributeView(dir, PosixFileAttributeView.class);
                if (posixAttrs != null) {
                    PosixFileAttributes sourcePosix = posixAttrs
                        .readAttributes();
                    PosixFileAttributeView targetPosix = Files
                        .getFileAttributeView(targetDir,
                            PosixFileAttributeView.class);
                    targetPosix.setPermissions(sourcePosix.permissions());
                    targetPosix.setGroup(sourcePosix.group());
                }
                UserDefinedFileAttributeView userAttrs = Files
                    .getFileAttributeView(dir,
                        UserDefinedFileAttributeView.class);
                if (userAttrs != null) {
                    UserDefinedFileAttributeView targetUser = Files
                        .getFileAttributeView(targetDir,
                            UserDefinedFileAttributeView.class);
                    for (String key : userAttrs.list()) {
                        ByteBuffer buffer = ByteBuffer.allocate(userAttrs
                            .size(key));
                        userAttrs.read(key, buffer);
                        buffer.flip();
                        targetUser.write(key, buffer);
                    }
                }
                // Must be done last, otherwise last-modified time may be
                // wrong
                BasicFileAttributeView targetBasic = Files
                    .getFileAttributeView(targetDir,
                        BasicFileAttributeView.class);
                targetBasic.setTimes(sourceBasic.lastModifiedTime(),
                    sourceBasic.lastAccessTime(),
                    sourceBasic.creationTime());
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file,
                    BasicFileAttributes attrs) throws IOException {
                Files.copy(file, target.resolve(source.relativize(file)),
                    StandardCopyOption.COPY_ATTRIBUTES);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult
                    visitFileFailed(Path file, IOException e)
                            throws IOException {
                throw e;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir,
                    IOException e) throws IOException {
                if (e != null) throw e;
                return FileVisitResult.CONTINUE;
            }
        });
}

This code hasn't been tested extensively, but it works for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top