com.flexive.shared.FxFileUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.flexive.shared.FxFileUtils.java

Source

/***************************************************************
 *  This file is part of the [fleXive](R) framework.
 *
 *  Copyright (c) 1999-2014
 *  UCS - unique computing solutions gmbh (http://www.ucs.at)
 *  All rights reserved
 *
 *  The [fleXive](R) project is free software; you can redistribute
 *  it and/or modify it under the terms of the GNU Lesser General Public
 *  License version 2.1 or higher as published by the Free Software Foundation.
 *
 *  The GNU Lesser General Public License can be found at
 *  http://www.gnu.org/licenses/lgpl.html.
 *  A copy is found in the textfile LGPL.txt and important notices to the
 *  license from the author are found in LICENSE.txt distributed with
 *  these libraries.
 *
 *  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 General Public License for more details.
 *
 *  For further information about UCS - unique computing solutions gmbh,
 *  please see the company website: http://www.ucs.at
 *
 *  For further information about [fleXive](R), please see the
 *  project website: http://www.flexive.org
 *
 *
 *  This copyright notice MUST APPEAR in all copies of the file!
 ***************************************************************/
package com.flexive.shared;

import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.List;

/**
 * Utilities for file system access
 *
 * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
 * @since 3.1
 */
public class FxFileUtils {
    private static final Log LOG = LogFactory.getLog(FxFileUtils.class);

    /**
     * Expand the path by replacing '~' with the user home directory and fix file separator chars
     *
     * @param path the path to expand
     * @return expanded path
     */
    public static String expandPath(String path) {
        //fix file separators
        if (File.separatorChar == '/')
            path = path.replace('\\', '/');
        else
            path = path.replace('/', '\\');
        //expand ~ to user home
        if (path.indexOf("~") >= 0)
            path = path.replaceAll("~", System.getProperty("user.home"));
        return path;
    }

    /**
     * Remove the given file
     *
     * @param fileName file to remove
     */
    public static void removeFile(String fileName) {
        if (StringUtils.isEmpty(fileName))
            return;
        removeFile(new File(fileName));
    }

    /**
     * Remove the given file
     *
     * @param file file to remove
     */
    public static void removeFile(File file) {
        if (file == null || !file.exists())
            return;
        if (!file.delete())
            file.deleteOnExit();
    }

    /**
     * Copy data from source to destination nio channel
     *
     * @param source      source channel
     * @param destination destination channel
     * @return total number of bytes copied
     * @throws java.io.IOException on errors
     */
    public static long copyNIOChannel(ReadableByteChannel source, WritableByteChannel destination)
            throws IOException {
        ByteBuffer xferBuffer = ByteBuffer.allocateDirect(4096);
        long count = 0, read, written;
        while (true) {
            read = source.read(xferBuffer);
            if (read < 0)
                return count;
            xferBuffer.flip();
            written = destination.write(xferBuffer);
            if (written > 0) {
                count += written;
                if (xferBuffer.hasRemaining())
                    xferBuffer.compact();
                else
                    xferBuffer.clear();
            } else {
                while (xferBuffer.hasRemaining()) {
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        LOG.warn(e);
                    }
                    written = destination.write(xferBuffer);
                    if (written > 0) {
                        count += written;
                        if (xferBuffer.hasRemaining())
                            xferBuffer.compact();
                    }
                }
                if (!xferBuffer.hasRemaining())
                    xferBuffer.clear();
            }
        }
    }

    /**
     * Copy a file
     *
     * @param source      source file
     * @param destination destination file
     * @return success
     */
    public static boolean copyFile(File source, File destination) {
        FileChannel sourceChannel = null;
        FileChannel destinationChannel = null;
        try {
            sourceChannel = new FileInputStream(source).getChannel();
            destinationChannel = new FileOutputStream(destination).getChannel();
            // don't use transferTo because it fails for large files under windows - http://bugs.sun.com/view_bug.do?bug_id=6431344
            return copyNIOChannel(sourceChannel, destinationChannel) == source.length()
                    && destination.length() == source.length();
        } catch (IOException e) {
            LOG.error(e, e);
            return false;
        } finally {
            try {
                if (sourceChannel != null)
                    sourceChannel.close();
            } catch (IOException e) {
                LOG.error(e);
            }
            try {
                if (destinationChannel != null)
                    destinationChannel.close();
            } catch (IOException e) {
                LOG.error(e);
            }
        }
    }

    /**
     * Copy the content of an InputStream to a file
     *
     * @param expectedSize    expected size of the stream
     * @param sourceStream    source
     * @param destinationFile destination
     * @return copy was successful and sizes match
     */
    public static boolean copyStream2File(long expectedSize, InputStream sourceStream, File destinationFile) {
        ReadableByteChannel sourceChannel = null;
        FileChannel destinationChannel = null;
        try {
            sourceChannel = Channels.newChannel(sourceStream);
            destinationChannel = new FileOutputStream(destinationFile).getChannel();
            return copyNIOChannel(sourceChannel, destinationChannel) == expectedSize
                    && destinationFile.length() == expectedSize;
        } catch (IOException e) {
            LOG.error(e, e);
            return false;
        } finally {
            try {
                if (sourceChannel != null)
                    sourceChannel.close();
            } catch (IOException e) {
                LOG.error(e);
            }
            try {
                if (destinationChannel != null)
                    destinationChannel.close();
            } catch (IOException e) {
                LOG.error(e);
            }
        }
    }

    /**
     * Move a file if possible, fallback to normal copy/delete if it fails.
     *
     * @param source         the source file
     * @param destination    the target file
     * @return  true on success
     * @since 3.2.0
     */
    public static boolean moveFile(File source, File destination) {
        if (!source.renameTo(destination)) {
            if (!copyFile(source, destination)) {
                return false;
            }
            removeFile(source);
        }
        return true;
    }

    /**
     * Remove a directory and all its sub directories and files
     *
     * @param dir directory to remove recursively
     */
    public static void removeDirectory(String dir) {
        if (StringUtils.isEmpty(dir))
            return;
        removeDirectory(new File(dir));
    }

    /**
     * Remove a directory and all its sub directories and files
     *
     * @param dir directory to remove recursively
     */
    public static void removeDirectory(File dir) {
        if (dir == null || !dir.exists())
            return;
        if (dir.isDirectory())
            for (File file : dir.listFiles())
                removeDirectory(file);
        removeFile(dir);
    }

    /**
     * Compare if two files match. Currently this method loads both files into memory and compares them,
     * so don't use this on arbitrarily large files.
     *
     * @param file1 first file to compare
     * @param file2 second file to compare
     * @return match
     */
    public static boolean fileCompare(File file1, File file2) {
        try {
            return file2.length() == file1.length() && Arrays.equals(getBytes(file2), getBytes(file1));
        } catch (IOException e) {
            if (LOG.isWarnEnabled()) {
                LOG.warn("Failed to compare files: " + e.getMessage(), e);
            }
            return false;
        }
    }

    /**
     * Load a file into a byte array
     *
     * @param file the file to load
     * @return byte[]
     * @throws IOException on errors
     */
    public static byte[] getBytes(File file) throws IOException {
        InputStream is = null;
        if (file.length() > Integer.MAX_VALUE)
            throw new IOException("File " + file.getAbsolutePath() + " is too large!");

        byte[] bytes = new byte[(int) file.length()];
        try {
            is = new FileInputStream(file);

            int curr = 0;
            int read;
            while (curr < bytes.length && (read = is.read(bytes, curr, bytes.length - curr)) >= 0)
                curr += read;
            if (curr < bytes.length)
                throw new IOException("Failed to fully read " + file.getAbsolutePath() + "!");
        } finally {
            if (is != null)
                is.close();
        }
        return bytes;
    }

    /**
     * Load a file and base64 encode it
     *
     * @param file the file to load
     * @return base64 encoded file content
     * @throws IOException on errors
     */
    public static String loadBase64Encoded(File file) throws IOException {
        if (file == null || !file.exists() || file.length() == 0)
            return "";
        return FxFormatUtils.encodeBase64(getBytes(file));
    }

    /**
     * List the contents of the given directory recursively.
     *
     * @param root  the root directory
     * @return      the contents of the directory
     */
    public static List<File> listRecursive(File root) {
        if (root == null || !root.exists()) {
            return Lists.newArrayListWithCapacity(0);
        }
        final List<File> result = Lists.newArrayList();
        final File[] files = root.listFiles();
        if (files == null) {
            if (LOG.isWarnEnabled()) {
                LOG.warn("Cannot list " + root.getPath() + " (not a directory?)");
            }
            return Lists.newArrayListWithCapacity(0);
        }
        for (File file : files) {
            if (file.isDirectory()) {
                result.addAll(listRecursive(file));
            } else {
                result.add(file);
            }
        }
        return result;
    }
}