org.kalypso.commons.java.io.FileUtilities.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.commons.java.io.FileUtilities.java

Source

/*--------------- Kalypso-Header --------------------------------------------------------------------
    
 This file is part of kalypso.
 Copyright (C) 2004, 2005 by:
    
 Technical University Hamburg-Harburg (TUHH)
 Institute of River and coastal engineering
 Denickestr. 22
 21073 Hamburg, Germany
 http://www.tuhh.de/wb
    
 and
    
 Bjoernsen Consulting Engineers (BCE)
 Maria Trost 3
 56070 Koblenz, Germany
 http://www.bjoernsen.de
    
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
    
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
    
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
 Contact:
    
 E-Mail:
 belger@bjoernsen.de
 schlienger@bjoernsen.de
 v.doemming@tuhh.de
    
 ---------------------------------------------------------------------------------------------------*/
package org.kalypso.commons.java.io;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.kalypso.commons.KalypsoCommonsPlugin;
import org.kalypso.commons.internal.i18n.Messages;
import org.kalypso.contribs.eclipse.core.runtime.StatusUtilities;
import org.kalypso.contribs.java.io.FileVisitor;

/**
 * Utility class for io and files
 * 
 * @author schlienger
 */
public class FileUtilities {
    public static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; //$NON-NLS-1$

    /** regex defining which are the invalid characters for a file name */
    public final static String INVALID_CHARACTERS = "[\\\\/:\\*\\?\"<>|]"; //$NON-NLS-1$

    /**
     * THE system tmp dir "java.io.tmpdir"
     */
    public static final File TMP_DIR = new File(System.getProperty(JAVA_IO_TMPDIR));

    /**
     * Rekursives lschen von Dateien und Verzeichnissen
     * 
     * @param file
     *          Falls das Argument eine Datei ist, wird diese gelscht. Ist es ein Verzeichnis, wird dieses mitsamt aller
     *          darin liegenden Verzeichnisse und Dateien gelscht.
     */
    public static void deleteRecursive(final File file) {
        if (file == null)
            return;

        if (file.isDirectory()) {
            final File[] files = file.listFiles();
            if (files != null) {
                for (final File element : files)
                    deleteRecursive(element);
            }
        }

        file.delete();
    }

    public static File mkTempFile() {
        final long millis = Calendar.getInstance().getTimeInMillis();

        return new File(TMP_DIR, Long.valueOf(millis).toString());
    }

    /**
     * This function creates a file handle in the temporary directory. It ensures, that the file does not exist already.
     * 
     * @param prefix
     *          The prefix will be used in front of the generated name. If empty or null it will be <xode>tmp</code>.
     * @param extension
     *          The extension of the temporary file. If empty or null it will be <xode>dat</code>.
     * @return A file handle in the temporary directory, whose file does not exist.
     */
    public static File getNewTempFile(String prefix, String extension) {
        /* A prefix is needed. */
        if (prefix == null || prefix.length() == 0)
            prefix = "tmp"; //$NON-NLS-1$

        /* An extension is needed. */
        if (extension == null || extension.length() == 0)
            extension = "dat"; //$NON-NLS-1$

        /* Create a new file handle, as long as the file exists. */
        File tmpFile = new File(FileUtilities.TMP_DIR,
                String.format("%s_%s.%s", prefix, String.valueOf(System.currentTimeMillis()), extension)); //$NON-NLS-1$
        while (tmpFile.exists())
            tmpFile = new File(FileUtilities.TMP_DIR,
                    String.format("%s_%s.%s", prefix, String.valueOf(System.currentTimeMillis()), extension)); //$NON-NLS-1$

        return tmpFile;
    }

    /**
     * Creates a temp directory in java.io.tmpdir.
     * 
     * @param prefix
     * @return temporary directory
     * @see FileUtilities#createNewTempDir(String, File )
     */
    public static File createNewTempDir(final String prefix) {
        return createNewTempDir(prefix, TMP_DIR);
    }

    /**
     * Creates a temp directory inside the given one. It uses <code>System.currentTimeMillis</code> for naming the new
     * temp dir. This method can hang a little while in the case the directory it tries to create already exist.
     * 
     * @param prefix
     * @param parentDir
     * @return temporary directory
     */
    public synchronized static File createNewTempDir(final String prefix, final File parentDir) {
        while (true) {
            final File newDir = new File(parentDir, prefix + System.currentTimeMillis());
            if (newDir.mkdirs())
                return newDir;
        }
    }

    /**
     * Creates a temp file inside the given folder. It uses <code>System.currentTimeMillis</code> for naming the new temp
     * file. This method can hang a little while in the case the file it tries to create already exist.
     * 
     * @param prefix
     * @param parentDir
     * @return unique file
     */
    public synchronized static File createNewUniqueFile(final String prefix, final File parentDir) {
        File newFile = new File(parentDir, prefix + System.currentTimeMillis());
        while (newFile.exists())
            newFile = new File(parentDir, prefix + System.currentTimeMillis());

        return newFile;
    }

    /**
     * Creates a unique file name inside the given folder. It uses <code>System.currentTimeMillis</code> for creating the
     * new file name. This method can hang a little while in the case the file it tries to create already exist.
     * 
     * @param prefix
     * @param extension
     * @param parentDir
     * @return unique file
     */
    public synchronized static String createNewUniqueFileName(final String prefix, final String extension,
            final File parentDir) {
        String newFileName = new String(prefix + "_" + System.currentTimeMillis() + extension); //$NON-NLS-1$
        File newFile = new File(parentDir, newFileName);
        while (newFile.exists()) {
            newFileName = new String(prefix + "_" + System.currentTimeMillis() + extension); //$NON-NLS-1$
            newFile = new File(parentDir, newFileName);
        }
        return newFileName;
    }

    /**
     * Creates a unique file name inside the given folder. It adds a counter between prefix and extension for creating the
     * new file name.<br>
     * First try is parent/prefix.extension
     * 
     * @param prefix
     * @param extension
     * @param parentDir
     * @return unique file
     */
    public synchronized static File createNewUniqueFile(final String prefix, final String extension,
            final File parentDir) {
        File newFile = new File(parentDir, prefix + extension);

        int count = 0;
        while (newFile.exists()) {
            final String newFileName = new String(prefix + "_" + count++ + extension); //$NON-NLS-1$
            newFile = new File(parentDir, newFileName);
        }
        return newFile;
    }

    /**
     * Macht aus einer absoluten Dateiangabe eine relative
     * 
     * @param basedir
     * @param absoluteFile
     * @return Ein File-Object, welches einen relativen Pfad enth?lt; null, wenn <code>basedir</code> kein Parent-Dir von <code>absoluteFile</code> ist
     */
    public static File getRelativeFileTo(final File basedir, final File absoluteFile) {
        final String rel = getRelativePathTo(basedir, absoluteFile);

        final File file = new File("." + rel); //$NON-NLS-1$
        return file;
    }

    /**
     * Returns the relative path, without any reserved characters such as '.'. This is meant to be used without string
     * concatenation function to reproduce an absolute path again. Directly creating a File object on the path returned by
     * this method won't produce a good result. Use the <code>getRelativeFileTo()</code> method instead.
     * 
     * @param basedir
     *          if null, the absolute path of absoluteFile is returned.
     * @param absoluteFile
     * @return the relative path from absoluteFile to basedir
     */
    public static String getRelativePathTo(final File basedir, final File absoluteFile) {
        if (basedir == null)
            return absoluteFile.getAbsolutePath();
        final String baseAbs = basedir.getAbsolutePath();
        final String absAbs = absoluteFile.getAbsolutePath();
        return getRelativePathTo(baseAbs, absAbs);
    }

    public static String getRelativePathTo(final String base, final String absolute) {
        final String separator = "/"; //$NON-NLS-1$
        String basePath = base.replaceAll("\\\\", separator); //$NON-NLS-1$
        final String absolutePath = absolute.replaceAll("\\\\", separator); //$NON-NLS-1$
        if (!absolutePath.startsWith(basePath)) {
            if (basePath.lastIndexOf(separator) > -1)
                basePath = basePath.substring(0, basePath.lastIndexOf(separator) + 1);

            final String difference = StringUtils.difference(basePath, absolutePath);
            if (difference == null || "".equals(difference)) //$NON-NLS-1$
                return null;

            final int index = absolutePath.indexOf(difference);
            if (index < 5)
                return null;

            final String back = basePath.substring(index);
            // TODO change regExp to "everything except fileseparator"
            final String x = back.replaceAll("([a-zA-Z0-9_-]|\\.)+", ".."); //$NON-NLS-1$ //$NON-NLS-2$
            if (x.length() > 0)
                // return x + "/" + difference; //$NON-NLS-1$
                return x + difference;

            return difference;
        }
        if (absolutePath.equalsIgnoreCase(basePath))
            return ""; //$NON-NLS-1$
        if (basePath.endsWith(separator))
            return absolutePath.substring(basePath.length());
        else
            return absolutePath.substring(basePath.length() + 1);
    }

    /**
     * Returns true if childCandidate is stored under the path of parent, either directly or in a sub directory.
     * 
     * @param parent
     * @param childCandidate
     * @return true if childCandidate is a child of the given parent.
     */
    public static boolean isChildOf(final File parent, final File childCandidate) {
        File f = childCandidate;

        while (f != null) {
            if (f.equals(parent))
                return true;

            f = f.getParentFile();
        }

        return false;
    }

    /**
     * @param name
     *          name of path of the file
     * @return characters after last "." of given file name
     */
    public static String getSuffix(final String name) {
        final String[] strings = name.split("\\."); //$NON-NLS-1$
        if (strings.length != 0)
            return strings[strings.length - 1];
        return null;
    }

    /**
     * @param file
     * @return characters after last "." of given file name
     */
    public static String getSuffix(final File file) {
        return getSuffix(file.getAbsolutePath());
    }

    /**
     * Returns only the name part of the given file name removing the extension part.
     * <p>
     * Example:
     * 
     * <pre>
     *     test.foo -- test
     *     robert.tt -- robert
     * </pre>
     * 
     * @param fileName
     * @return fileName without the last '.???' extension part (NOTE: the extension part is not limited to 3 chars)
     */
    public static String nameWithoutExtension(final String fileName) {
        final int lastIndexOf = fileName.lastIndexOf('.');
        if (lastIndexOf == -1)
            return fileName;

        return fileName.substring(0, lastIndexOf);
    }

    /**
     * Lsst den FileVisitor die angegebene Datei bzw. Verzeichnis und alle darin enthaltenen Dateien besuchen.
     * 
     * @param recurse
     *          Falls true, werden auch Unterverzeichnisse besucht
     * @throws IOException
     */
    public static void accept(final File root, final FileVisitor visitor, final boolean recurse)
            throws IOException {
        if (!root.exists())
            return;

        // zuerst die Datei selbst
        final boolean stop = !visitor.visit(root);
        if (stop || !root.isDirectory())
            return;

        final File[] files = root.listFiles();
        if (files == null)
            return;

        for (final File file : files) {
            if (file.isFile() || file.isDirectory() && recurse)
                accept(file, visitor, recurse);
        }
    }

    public static void copyShapeFileToDirectory(final String shapeBase, final File target) {
        File _shp;
        File _dbf;
        File _shx;
        File _sbn;
        File _sbx;
        if (target.isDirectory()) {
            try {
                _shp = new File(shapeBase + ".shp"); //$NON-NLS-1$
                if (_shp.exists())
                    FileUtils.copyFileToDirectory(_shp, target);
                else
                    return;
                _dbf = new File(shapeBase + ".dbf"); //$NON-NLS-1$
                if (_dbf.exists())
                    FileUtils.copyFileToDirectory(_dbf, target);
                else
                    return;
                _shx = new File(shapeBase + ".shx"); //$NON-NLS-1$
                if (_shx.exists())
                    FileUtils.copyFileToDirectory(_shx, target);
                else
                    return;
                _sbn = new File(shapeBase + ".sbn"); //$NON-NLS-1$
                if (_sbn.exists())
                    FileUtils.copyFileToDirectory(_sbn, target);
                _sbx = new File(shapeBase + ".sbx"); //$NON-NLS-1$
                if (_sbn.exists())
                    FileUtils.copyFileToDirectory(_sbx, target);

            } catch (final MalformedURLException e) {
                e.printStackTrace();
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Replaces all invalid characters from the given fileName so that it is valid against the OS-rules for naming files.
     * 
     * @return a valid filename that can be used to create a new file, special (invalid) characters are removed and
     *         replaced by the given replacement-string
     */
    public static String validateName(final String fileName, final String replacement) {
        return fileName.replaceAll(INVALID_CHARACTERS, replacement);
    }

    /**
     * Gets the name part of a path-like-string.
     * <p>
     * That is, everything after the last '/' or '\'.
     * </p>
     * <p>
     * E.g. <code>C:/mydirectory/file.txt</code> gets <code>file.txt</code>
     * </p>
     * .
     */
    public static String nameFromPath(final String path) {
        final int lastIndexOfSlash = path.lastIndexOf('/');

        /**
         * Bug fixed by Dejan, 18.01.2007 It was final int lastIndexOfBackslash = path.lastIndexOf( '\\' ); i.e. the same
         * value as lastIndexOfSlash, so it was not working for backslashes TODO: consider using java.io.File.separatorChar
         * instead of slash & backslash
         */
        final int lastIndexOfBackslash = path.lastIndexOf('\\');

        final int lastIndexOf = Math.max(lastIndexOfSlash, lastIndexOfBackslash);

        if (lastIndexOf == -1)
            return path;

        if (lastIndexOf + 1 == path.length() - 1)
            return ""; //$NON-NLS-1$

        return path.substring(lastIndexOf + 1);
    }

    /**
     * Sets a certain suffix to the given file name. If the file name already has a suffix (that is a non-empty string
     * after the last '.') it will be replaced.
     * 
     * @param suffix
     *          The suffix without the point '.'
     */
    public static String setSuffix(final String fileName, final String suffix) {
        final int index = fileName.lastIndexOf('.');
        if (index == -1)
            return fileName + '.' + suffix;

        return fileName.substring(0, index) + suffix;
    }

    /**
     * Copies the content of a url into a string.
     * 
     * @param encoding
     *          The encoding to read the content, if <code>null</code> the platforms default encoding will be used.
     */
    public static String toString(final URL input, final String encoding) throws IOException {
        InputStream is = null;
        try {
            is = input.openStream();

            if (encoding == null)
                return IOUtils.toString(is);

            return IOUtils.toString(is, encoding);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    /**
     * Replaces all invalid characters from the given fileName so that it is valid against the OS-rules for naming files.
     * and looks if file already exists in baseFolder
     * 
     * @return a valid filename that can be used to create a new file, special (invalid) characters are removed and
     *         replaced by the given replacement-string
     */
    public static String validateName(final IFolder baseFolder, final String name, final String replacement) {
        final String myBaseName = validateName(name, replacement);
        String myName = myBaseName;

        int count = 0;
        while (baseFolder.getFile(myName).exists()) {
            myName = String.format("%s%d", myBaseName, count); //$NON-NLS-1$
            count++;
        }

        return myName;
    }

    /**
     * This function deletes files/directories from the list, which are older than 'days' days. <br />
     * Be aware, that it <strong>deletes all directories recursively</strong>.<br />
     * So if one directory contains files, you want to keep, do not add this directory, but only the child
     * files/directories you realy want to delete.
     * 
     * @param files
     *          The files/directories to check for deletion. All files/directories older than 'days' days will be deleted.
     * @param days
     *          The days, to keep the files and directories.
     * @return A multi status, containing the result for each file, which was tried to delete.
     */
    public static MultiStatus deleteFiles(final List<File> files, final int days) {
        /* The date 'days' before now. */
        final Calendar before = Calendar.getInstance();
        before.add(Calendar.DAY_OF_MONTH, -days);

        /* Check the date of the files, each file older than 'days' will be deleted. */
        final List<File> filesToDelete = new ArrayList<>();

        for (int i = 0; i < files.size(); i++) {
            /* Get the file. */
            final File file = files.get(i);

            /* Using the last modified time should not hurt. */
            final long lastModified = file.lastModified();
            if (lastModified < before.getTimeInMillis())
                filesToDelete.add(file);
        }

        /* List for success or error messages. */
        final MultiStatus stati = new MultiStatus(KalypsoCommonsPlugin.getID(), IStatus.OK,
                Messages.getString("org.kalypso.commons.java.io.FileUtilities.1", String.valueOf(days)), null); //$NON-NLS-1$

        /* Delete these files. */
        for (int i = 0; i < filesToDelete.size(); i++) {
            /* Get the file/directory to delete. */
            final File fileToDelete = filesToDelete.get(i);

            if (!fileToDelete.exists())
                continue;

            try {
                /* Delete file or the directory and its contents. */
                FileUtilities.deleteRecursive(fileToDelete);

                /* Add the success message. */
                stati.add(new Status(IStatus.OK, KalypsoCommonsPlugin.getID(), fileToDelete.getName() + ": OK")); //$NON-NLS-1$
            } catch (final Exception ex) {
                /* If one could no be deleted, it does not matter, the next run will get it. We will get them all :). */
                final IStatus status = StatusUtilities.statusFromThrowable(ex,
                        fileToDelete.getName() + ": NOT DELETED"); //$NON-NLS-1$
                stati.add(status);
            }
        }

        return stati;
    }

    public static String resolveValidFileName(String fileName) {
        fileName = fileName.replaceAll("\\\\", "_"); //$NON-NLS-1$ //$NON-NLS-2$
        fileName = fileName.replaceAll("/", "_"); //$NON-NLS-1$ //$NON-NLS-2$
        fileName = fileName.replaceAll(":", "_"); //$NON-NLS-1$ //$NON-NLS-2$
        fileName = fileName.replaceAll("\\.", "_"); //$NON-NLS-1$ //$NON-NLS-2$

        return fileName.trim();
    }

    public static File[] getFiles(final File fDir, final String regex) {
        Assert.isTrue(fDir.isDirectory());
        final String myRegEx = regex.toLowerCase();

        final File[] files = fDir.listFiles(new FileFilter() {
            @Override
            public boolean accept(final File pathname) {
                final String name = pathname.getName().toLowerCase();
                if (name.matches(myRegEx))
                    return true;

                return false;
            }
        });

        return files;
    }

    public static void deleteQuietly(final File file) {
        try {
            if (!file.exists())
                return;

            FileUtils.forceDelete(file);
        } catch (final IOException e) {
            KalypsoCommonsPlugin.getDefault().getLog()
                    .log(new Status(IStatus.ERROR, KalypsoCommonsPlugin.getID(), e.getLocalizedMessage(), e));
        }
    }

    /**
     * @return complete file name including suffix
     */
    public static String resolveFileName(final String file) {
        final int index = findLastSeperator(file);
        if (index == -1)
            return file;

        return file.substring(index + 1);
    }

    public static int findLastSeperator(final String file) {
        if (file.contains("/")) //$NON-NLS-1$
            return file.lastIndexOf("/"); //$NON-NLS-1$
        else if (file.contains("\\")) //$NON-NLS-1$
            return file.lastIndexOf("\\"); //$NON-NLS-1$

        return -1;
    }

    public static void cleanDirectory(final File dir, final IFileFilter filter) {
        final File[] files = dir.listFiles();
        for (final File file : files) {
            if (filter.select(file))
                FileUtilities.deleteQuietly(file);
        }
    }

    public static File findExecutableOnPath(final String executableName) {
        final String systemPath = System.getenv("PATH"); //$NON-NLS-1$  
        final String[] pathDirs = systemPath.split(File.pathSeparator);
        for (final String pathDir : pathDirs) {
            final File file = new File(pathDir, executableName);
            if (file.isFile())
                return file;
        }
        // not found on path
        return null;
    }

}