All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.marschall.memoryfilesystem.Directories Maven / Gradle / Ivy

The newest version!
package com.github.marschall.memoryfilesystem;

import static java.nio.file.FileVisitResult.CONTINUE;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.CopyOption;
import java.nio.file.FileSystemException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.DosFileAttributeView;
import java.nio.file.attribute.DosFileAttributes;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.attribute.GroupPrincipal;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.UserDefinedFileAttributeView;
import java.nio.file.attribute.UserPrincipal;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.nio.file.attribute.UserPrincipalNotFoundException;
import java.util.HashSet;
import java.util.Set;

/**
 * Implements recursive copy missing in {@link Files}.
 */
public final class Directories {

  private static final LinkOption[] NO_LINK_OPTIONS = new LinkOption[0];
  private static final LinkOption[] NOFOLLOW_LINKS = new LinkOption[]{LinkOption.NOFOLLOW_LINKS};


  private Directories() {
    throw new AssertionError("not instantiable");
  }


  /**
   * Copy a directory to a target directory recursively.
   *
   * 

This method performs a copy much like * {@link Files#copy(Path, Path, CopyOption...)}. Unlike * {@link Files#copy(Path, Path, CopyOption...)} is can also copy non-empty * directories.

* *

This method makes a best effort to copy attributes across * different file system providers.

* *

Known Issues:

*
    *
  • hard links will not be handled correctly
  • *
* * @see Files#copy(Path, Path, CopyOption...) * * @param source the path to the file to copy * @param target the path to the target file (may be associated with a different * provider to the source path) * @param copyOptions options specifying how the copy should be done * @throws IOException if an I/O error occurs */ public static void copyRecursive(Path source, Path target, CopyOption... copyOptions) throws IOException { boolean sameFileSystem = source.getFileSystem() == target.getFileSystem(); LinkOption[] linkOptions = linkOptions(copyOptions); boolean targetExists = Files.exists(target, linkOptions); boolean copyAttributes = Options.isCopyAttributes(copyOptions); Set> supportedAttributeViews = supportedAttributeViews(source, target, sameFileSystem); if (!targetExists) { Files.createDirectories(target); } FileVisitor copier = new DirectoryCopier(source, target, copyOptions, linkOptions, supportedAttributeViews, sameFileSystem, copyAttributes); Files.walkFileTree(source, copier); if (!targetExists && copyAttributes) { copyAttributes(source, target, sameFileSystem, supportedAttributeViews, linkOptions); } } private static LinkOption[] linkOptions(CopyOption[] copyOptions) { return Options.isFollowSymLinks(copyOptions) ? NO_LINK_OPTIONS : NOFOLLOW_LINKS; } private static Set> supportedAttributeViews(Path source, Path target, boolean sameFileSystem) { Set viewNames = source.getFileSystem().supportedFileAttributeViews(); if (!sameFileSystem) { viewNames = new HashSet<>(viewNames); // can be unmodifyable viewNames.retainAll(target.getFileSystem().supportedFileAttributeViews()); } Set> supportedAttribueViews = new HashSet<>(viewNames.size()); for (String string : viewNames) { supportedAttribueViews.add(FileAttributeViews.mapAttributeViewName(string)); } return supportedAttribueViews; } private static void copyAttributes(Path source, Path target, boolean sameFileSystem, Set> attributeViews, LinkOption[] linkOptions) throws IOException { BasicFileAttributes basicAttributes = Files.readAttributes(target, BasicFileAttributes.class, linkOptions); BasicFileAttributeView basicView = Files.getFileAttributeView(target, BasicFileAttributeView.class, linkOptions); basicView.setTimes(basicAttributes.lastModifiedTime(), basicAttributes.lastAccessTime(), basicAttributes.creationTime()); if (attributeViews.contains(PosixFileAttributeView.class)) { PosixFileAttributes posixAttributes = Files.readAttributes(target, PosixFileAttributes.class, linkOptions); PosixFileAttributeView posixView = Files.getFileAttributeView(target, PosixFileAttributeView.class, linkOptions); posixView.setPermissions(posixAttributes.permissions()); copyOwner(source, target, sameFileSystem, posixAttributes, posixView, linkOptions); copyGroup(source, target, sameFileSystem, posixAttributes, posixView, linkOptions); } if (attributeViews.contains(UserDefinedFileAttributeView.class)) { UserDefinedFileAttributeView sourceAttributes = Files.getFileAttributeView(source, UserDefinedFileAttributeView.class, linkOptions); UserDefinedFileAttributeView targetAttributes = Files.getFileAttributeView(target, UserDefinedFileAttributeView.class, linkOptions); // try to reuse the buffer // TODO reuse buffer across files ByteBuffer buffer = null; for (String each : sourceAttributes.list()) { int size = sourceAttributes.size(each); if (buffer == null) { buffer = ByteBuffer.allocate(size); } else { buffer.reset(); if (buffer.capacity() < size) { buffer = ByteBuffer.allocate(size); } } int read = sourceAttributes.read(each, buffer); if (read != size) { throw new FileSystemException(source.toString(), null,"could not read attribute: " + each); } buffer.flip(); int written = targetAttributes.write(each, buffer); if (written != size) { throw new FileSystemException(target.toString(), null, "could not read attribute: " + each); } } } if (attributeViews.contains(DosFileAttributeView.class)) { DosFileAttributes dosAttributes = Files.readAttributes(target, DosFileAttributes.class, linkOptions); DosFileAttributeView dosView = Files.getFileAttributeView(target, DosFileAttributeView.class, linkOptions); dosView.setArchive(dosAttributes.isArchive()); dosView.setHidden(dosAttributes.isHidden()); dosView.setSystem(dosAttributes.isSystem()); dosView.setReadOnly(dosAttributes.isReadOnly()); } } private static void copyOwner(Path source, Path target, boolean sameFileSystem, PosixFileAttributes posixAttributes, PosixFileAttributeView posixView, LinkOption[] linkOptions) throws IOException { UserPrincipal owner = posixAttributes.owner(); if (!sameFileSystem) { UserPrincipalLookupService userPrincipalLookupService = source.getFileSystem().getUserPrincipalLookupService(); try { owner = userPrincipalLookupService.lookupPrincipalByName(owner.getName()); } catch (UserPrincipalNotFoundException e) { // user doesn't exist in target file system, ignore return; } } posixView.setOwner(owner); } private static void copyGroup(Path source, Path target, boolean sameFileSystem, PosixFileAttributes posixAttributes, PosixFileAttributeView posixView, LinkOption[] linkOptions) throws IOException { GroupPrincipal group = posixAttributes.group(); if (!sameFileSystem) { UserPrincipalLookupService userPrincipalLookupService = source.getFileSystem().getUserPrincipalLookupService(); try { group = userPrincipalLookupService.lookupPrincipalByGroupName(group.getName()); } catch (UserPrincipalNotFoundException e) { // user doesn't exist in target file system, ignore return; } } posixView.setGroup(group); } static final class DirectoryCopier extends SimpleFileVisitor { private final Path source; private final Path target; private final LinkOption[] linkOptions; private final CopyOption[] copyOptions; private final boolean sameFileSystem; private final boolean copyAttributes; private final Set> supportedAttributeViews; DirectoryCopier(Path source, Path target, CopyOption[] copyOptions, LinkOption[] linkOptions, Set> supportedAttributeViews, boolean sameFileSystem, boolean copyAttributes) { this.source = source; this.target = target; this.copyOptions = copyOptions; this.linkOptions = linkOptions; this.supportedAttributeViews = supportedAttributeViews; this.sameFileSystem = sameFileSystem; this.copyAttributes = copyAttributes; } private Path relativize(Path path) { Path relativized = this.source.relativize(path); if (this.sameFileSystem) { // TODO would same provider be enough? return this.target.resolve(relativized); } else { return this.target.resolve(relativized.toString()); } } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.copy(file, this.relativize(file), this.copyOptions); return CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { if (!dir.equals(dir.getRoot())) { // skip creating root on target file system Files.createDirectory(this.relativize(dir)); } return CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if (this.copyAttributes) { copyAttributes(this.source, this.relativize(dir), this.sameFileSystem, this.supportedAttributeViews, this.linkOptions); } return CONTINUE; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy