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

net.sf.mmm.util.file.base.FileUtilImpl Maven / Gradle / Ivy

The newest version!
/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0
 * http://www.apache.org/licenses/LICENSE-2.0 */
package net.sf.mmm.util.file.base;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.mmm.util.file.api.FileAccessClass;
import net.sf.mmm.util.file.api.FileAlreadyExistsException;
import net.sf.mmm.util.file.api.FileAttributeModificationFailedException;
import net.sf.mmm.util.file.api.FileCreationFailedException;
import net.sf.mmm.util.file.api.FileDeletionFailedException;
import net.sf.mmm.util.file.api.FilePermissionException;
import net.sf.mmm.util.file.api.FileType;
import net.sf.mmm.util.file.api.FileUtil;
import net.sf.mmm.util.io.api.IoMode;
import net.sf.mmm.util.io.api.RuntimeIoException;
import net.sf.mmm.util.lang.api.BasicHelper;
import net.sf.mmm.util.resource.api.ResourcePathNode;

/**
 * This class is a collection of utility functions for {@link File} handling and manipulation.
 *
 * @see #getInstance()
 *
 * @author Joerg Hohwiller (hohwille at users.sourceforge.net)
 * @since 1.0.1
 */
public class FileUtilImpl extends FileUtilLimitedImpl implements FileUtil {

  private static final Logger LOG = LoggerFactory.getLogger(FileUtilImpl.class);

  private static FileUtil instance;

  private File userHomeDirectory;

  private String temporaryDirectoryPath;

  private File temporaryDirectory;

  /**
   * The constructor.
   */
  public FileUtilImpl() {

    super();
  }

  /**
   * This method gets the singleton instance of this {@link FileUtilImpl}. 
* ATTENTION:
* Please prefer dependency-injection instead of using this method. * * @return the singleton instance. */ public static FileUtil getInstance() { if (instance == null) { synchronized (FileUtilImpl.class) { if (instance == null) { FileUtilImpl util = new FileUtilImpl(); util.initialize(); instance = util; } } } return instance; } @Override protected void doInitialize() { super.doInitialize(); if (this.temporaryDirectoryPath == null) { this.temporaryDirectoryPath = System.getProperty(PROPERTY_TMP_DIR); } this.temporaryDirectoryPath = this.temporaryDirectoryPath.replace('\\', '/'); if (this.temporaryDirectory == null) { this.temporaryDirectory = new File(this.temporaryDirectoryPath); } if (this.userHomeDirectory == null) { this.userHomeDirectory = new File(BasicHelper.getUserHomePath()); } } @Override public File getUserHomeDirectory() { return this.userHomeDirectory; } @Override public File getTemporaryDirectory() { return this.temporaryDirectory; } /** * This method sets the {@link #getTemporaryDirectory() tmp directory}. * * @param tmpDir the tmpDir to set */ public void setTemporaryDirectoryPath(String tmpDir) { getInitializationState().requireNotInitilized(); this.temporaryDirectoryPath = tmpDir; } @Override public boolean mkdirs(File directory) { if (directory.isDirectory()) { return false; } boolean mkdirs = directory.mkdirs(); if (!mkdirs) { // retry (e.g. Windows filesystem can be picky) mkdirs = directory.mkdirs(); if (!mkdirs) { throw new FileCreationFailedException(directory, true); } } return true; } @Override public boolean ensureFileExists(File file) { if (file.exists()) { if (file.isDirectory()) { throw new FileCreationFailedException(file.getPath(), false); } return false; } else { File parent = file.getParentFile(); if (parent != null) { mkdirs(parent); } boolean created = false; try { created = file.createNewFile(); } catch (IOException e) { throw new FileCreationFailedException(e, file); } assert (file.isFile()); return created; } } @Override public boolean touch(File file) { boolean created = ensureFileExists(file); if (!file.canWrite()) { throw new FilePermissionException(file); } boolean touched = file.setLastModified(System.currentTimeMillis()); if (!touched) { throw new FileAttributeModificationFailedException(file); } return created; } @Override public void copyFile(File source, File destination) { // There is also Files.copy but its implementation does not seem as efficient... try (FileInputStream sourceStream = new FileInputStream(source); FileOutputStream destinationStream = new FileOutputStream(destination)) { FileChannel sourceChannel = sourceStream.getChannel(); sourceChannel.transferTo(0, sourceChannel.size(), destinationStream.getChannel()); } catch (IOException e) { throw new RuntimeIoException(e, IoMode.COPY); } } @Override public void copyFile(File source, File destination, boolean keepFlags) { copyFile(source, destination); if (keepFlags) { if (source.canExecute()) { destination.setExecutable(true, false); } boolean success = true; if (!source.canWrite()) { success = destination.setReadOnly(); } long lastModified = source.lastModified(); success = success && destination.setLastModified(lastModified); if (!success) { throw new FileAttributeModificationFailedException(destination); } } } @Override public void copyRecursive(File source, File destination, boolean allowOverwrite) { copyRecursive(source, destination, allowOverwrite, null); } @Override public void copyRecursive(File source, File destination, boolean allowOverwrite, FileFilter filter) { if (!allowOverwrite && (destination.exists())) { throw new FileAlreadyExistsException(destination); } copyRecursive(source, destination, filter); } /** * This method copies the file or directory given by {@code source} into the given {@code destination}.
* ATTENTION:
* In order to allow giving the copy of {@code source} a new {@link File#getName() name}, the {@code destination} has * to point to the final place where the copy should appear rather than the directory where the copy will be located * in.
*
* E.g. the following code copies the folder "foo" located in "/usr/local" recursively to the directory "/tmp". The * copy will have the same name "foo". * *
   * {@link File} source = new {@link File}("/usr/local/foo");
   * {@link File} destination = new {@link File}("/tmp", source.getName()); // file: "/tmp/foo"
   * {@link FileUtilImpl}.copyRecursive(source, destination, true);
   * 
* * @param source is the file or directory to copy. * @param destination is the final place where the copy should appear. * @param filter is a {@link FileFilter} that {@link FileFilter#accept(File) decides} which files should be copied. * Only {@link FileFilter#accept(File) accepted} files and directories are copied, others will be ignored. */ private void copyRecursive(File source, File destination, FileFilter filter) { if (source.isDirectory()) { boolean okay = destination.mkdir(); if (!okay) { throw new FileCreationFailedException(destination.getAbsolutePath(), true); } File[] children; if (filter == null) { children = source.listFiles(); } else { children = source.listFiles(filter); } for (File file : children) { copyRecursive(file, new File(destination, file.getName()), filter); } } else { copyFile(source, destination); } } @Override public FileAccessPermissions getPermissions(File file, FileAccessClass accessClass) { FileAccessPermissions permissions = new FileAccessPermissions(); boolean x = file.canExecute(); boolean w = file.canWrite(); boolean r = file.canRead(); if (accessClass == null) { permissions.setExecutable(x); permissions.setWritable(w); permissions.setReadable(r); } else { permissions.setExecutable(accessClass, x); permissions.setWritable(accessClass, w); permissions.setReadable(accessClass, r); } return permissions; } @Override public void setPermissions(File file, FileAccessPermissions permissions) { boolean success = true; // global permissions success = success & file.setExecutable(permissions.isExecutable(FileAccessClass.OTHERS)); success = success & file.setWritable(permissions.isWritable(FileAccessClass.OTHERS)); success = success & file.setReadable(permissions.isReadable(FileAccessClass.OTHERS)); // user permissions success = success & file.setExecutable(permissions.isExecutable(FileAccessClass.USER), true); success = success & file.setWritable(permissions.isWritable(FileAccessClass.USER), true); success = success & file.setReadable(permissions.isReadable(FileAccessClass.USER), true); if (!success) { throw new FileAttributeModificationFailedException(file); } } @Override public boolean delete(File file) throws FileDeletionFailedException { if (!file.exists()) { return false; } boolean deleted = file.delete(); if (deleted) { return true; } // retry... deleted = file.delete(); if (deleted) { LOG.debug("Deletion failed and succeeded after retry for file {}", file); return true; } throw new FileDeletionFailedException(file); } @Override public int deleteRecursive(File path) { return deleteRecursive(path, null); } @Override public int deleteRecursive(File path, FileFilter filter) throws RuntimeIoException { int deleteCount = 0; if (path.exists()) { if (path.isDirectory()) { deleteCount = deleteChildren(path, filter); if (filter == null) { delete(path); } else { boolean deleted = path.delete(); if (!deleted) { LOG.debug("Directory {} was not deleted.", path); } } } else if ((filter == null) || (filter.accept(path))) { deleteCount = 1; delete(path); } } return deleteCount; } @Override public int deleteChildren(File directory) { return deleteChildren(directory, null); } @Override public int deleteChildren(File directory, FileFilter filter) throws FileDeletionFailedException { int deleteCount = 0; File[] children = directory.listFiles(); if (children != null) { for (File file : children) { if (file.isDirectory()) { deleteCount += deleteChildren(file, filter); if (filter == null) { delete(file); } else { boolean deleted = file.delete(); if (!deleted) { LOG.trace("Directory {} was not deleted.", file); } } } else if ((filter == null) || (filter.accept(file))) { delete(file); deleteCount++; } } } return deleteCount; } @Override public File[] getMatchingFiles(File cwd, String path, FileType fileType) { List list = new ArrayList<>(); collectMatchingFiles(cwd, path, fileType, list); return list.toArray(new File[list.size()]); } @Override public boolean collectMatchingFiles(File cwd, String path, FileType fileType, Collection list) { if ((path == null) || (path.length() == 0)) { throw new IllegalArgumentException("Path must not be empty"); } ResourcePathNode patternPath = ResourcePathNode.createPattern(path); List> segments = patternPath.asList(); collectMatchingFiles(cwd, segments, 1, fileType, list); boolean hasPattern = false; for (ResourcePathNode segment : segments) { if (segment.getData() != null) { hasPattern = true; break; } } return hasPattern; } /** * This method adds all files matching with the given {@code path} and {@code fileType} to the {@code list}. * * @param cwd is the current working directory and should therefore point to an existing {@link File#isDirectory() * directory}. If the given {@code path} is NOT {@link File#isAbsolute() absolute} it is interpreted relative * to this directory. * @param segments is the path the files to collect must match. If this path is NOT {@link File#isAbsolute() absolute} * it is interpreted relative to the {@link File#isDirectory() directory} given by {@code cwd}. * @param segmentIndex is the current index in {@code pathChars} for the collection process. * @param fileType is the type of the files to collect or {@code null} if files of any type are acceptable. * @param list is the {@link Collection} where to {@link Collection#add(Object) add} the collected files. */ private void collectMatchingFiles(File cwd, List> segments, int segmentIndex, FileType fileType, Collection list) { boolean lastSegment; if ((segmentIndex + 1) < segments.size()) { lastSegment = false; } else { lastSegment = true; } ResourcePathNode currentSegment = segments.get(segmentIndex); Pattern pattern = currentSegment.getData(); if (pattern == null) { File newCwd = new File(cwd, currentSegment.getName()); if (newCwd.exists()) { if (lastSegment) { if ((fileType == null) || (FileType.getType(newCwd) == fileType)) { list.add(newCwd); } } else if (newCwd.isDirectory()) { collectMatchingFiles(newCwd, segments, segmentIndex + 1, fileType, list); } } } else if ("**".equals(currentSegment.getName())) { collectMatchingFiles(cwd, segments, segmentIndex + 1, fileType, list); File[] children = cwd.listFiles(DirectoryFilter.getInstance()); for (File file : children) { collectMatchingFiles(file, segments, segmentIndex, fileType, list); } } else { FileType filterType = fileType; if (!lastSegment) { filterType = FileType.DIRECTORY; } FileFilter filter = new PatternFileFilter(pattern, filterType); File[] children = cwd.listFiles(filter); if (lastSegment) { for (File file : children) { list.add(file); } } else { for (File file : children) { collectMatchingFiles(file, segments, segmentIndex + 1, fileType, list); } } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy