com.wavemaker.commons.util.IOUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.wavemaker.commons.util.IOUtils.java

Source

/**
 * Copyright  2013 - 2017 WaveMaker, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wavemaker.commons.util;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import javax.xml.stream.XMLStreamReader;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import com.wavemaker.commons.MessageResource;
import com.wavemaker.commons.WMRuntimeException;

/**
 * @author Simon Toens
 * @author Matt Small
 * @author Jeremy Grelle
 */
public abstract class IOUtils {

    private static final Logger logger = LoggerFactory.getLogger(IOUtils.class);

    private static final int DEFAULT_BUFFER_SIZE = 1024;

    private IOUtils() {
    }

    /**
     * List of our default exclusion directory names. This is used both by
     */
    public static final List<String> DEFAULT_EXCLUSION = Collections
            .unmodifiableList(Arrays.asList(new String[] { ".svn" }));

    /**
     * Read an entire File into a String.
     *
     * @param f The file to read from.
     * @return The contents of f as a String.
     * @throws IOException
     */
    public static String read(File f) throws IOException {
        StringBuilder fileSB = new StringBuilder();
        char[] buf = new char[DEFAULT_BUFFER_SIZE];

        BufferedReader br = null;

        try {

            br = new BufferedReader(new FileReader(f));

            while (br.ready()) {
                int readlen = br.read(buf);
                fileSB.append(buf, 0, readlen);
            }
            return fileSB.toString();

        } finally {
            closeSilently(br);
        }
    }

    /**
     * Read the bottom of a File into a String. This probably isn't the proper way to do this in java but my goals here
     * were limited to NOT flooding memory with the entire file, but just to grab the last N lines and never have more
     * than the last N lines in memory
     */
    public static String tail(File f, int lines) throws IOException {
        java.util.ArrayList<String> lineList = new java.util.ArrayList<String>(lines);

        BufferedReader br = null;

        try {

            br = new BufferedReader(new FileReader(f));

            while (br.ready()) {
                String s = br.readLine();
                if (s == null) {
                    break;
                } else {
                    lineList.add(s);
                }
                if (lineList.size() > lines) {
                    lineList.remove(0);
                }
            }
            StringBuilder fileSB = new StringBuilder();
            for (int i = 0; i < lineList.size(); i++) {
                fileSB.append(lineList.get(i) + "\n");
            }
            return fileSB.toString();

        } finally {
            closeSilently(br);
        }
    }

    public static void write(File f, String s) throws IOException {
        f.getParentFile().mkdirs();
        BufferedWriter br = null;
        try {
            br = new BufferedWriter(new FileWriter(f));
            br.write(s);
        } finally {
            closeSilently(br);
        }
    }

    public static boolean compare(InputStream i1, InputStream i2) throws IOException {
        int b1 = 0;

        while ((b1 = i1.read()) != -1) {

            int b2 = i2.read();

            if (b2 == -1) {
                return false;
            }

            if (b1 != b2) {
                return false;
            }

        }

        return i2.read() == -1;

    }

    // Returns the number of folders there are in the current folder; ignores
    // any folder with a "private" name (i.e. name starts with _ or .)
    public static int countFoldersInDir(File f) {
        int count = 0;
        try {
            File[] listing = f.listFiles();
            for (int i = 0; i < listing.length; i++) {
                if (listing[i].isDirectory() && !listing[i].getName().startsWith(".")
                        && !listing[i].getName().startsWith("_")) {
                    count++;
                }
            }

        } catch (Exception e) {
        }
        return count;
    }

    /**
     * Read content of InputStream is into OutputStream os.
     * @param is InputStream to read from.
     * @param os OutputStream to write to.
     * @param closeInputStream if true,closes input stream in both success/failure scenarios
     * @param closeOutputStream if true,closes output stream in both success/failure scenarios
     * @return returns the number of bytes actually written
     * @throws IOException
     */
    public static int copy(InputStream is, OutputStream os, boolean closeInputStream, boolean closeOutputStream)
            throws IOException {
        try {
            return org.apache.commons.io.IOUtils.copy(is, os);
        } finally {
            if (closeInputStream) {
                closeSilently(is);
            }
            if (closeOutputStream) {
                closeSilently(os);
            }
        }
    }

    /**
     * Copy from: file to file, directory to directory, file to directory. Defaults to exclude nothing, so all files and
     * directories are copied.
     *
     * @param source File object representing a file or directory to copy from.
     * @param destination File object representing the target; can only represent a file if the source is a file.
     * @throws IOException
     */
    public static void copy(File source, File destination) throws IOException {

        copy(source, destination, new ArrayList<String>());
    }

    /**
     * Copy from: file to file, directory to directory, file to directory.
     *
     * @param source File object representing a file or directory to copy from.
     * @param destination File object representing the target; can only represent a file if the source is a file.
     * @param excludes A list of exclusion filenames.
     * @throws IOException
     */
    public static void copy(File source, File destination, List<String> excludes) throws IOException {

        if (!source.exists()) {
            throw new IOException("Can't copy from non-existent file: " + source.getAbsolutePath());
        } else if (excludes.contains(source.getName())) {
            return;
        }

        if (source.isDirectory()) {
            if (!destination.exists()) {
                FileUtils.forceMkdir(destination);
            }
            if (!destination.isDirectory()) {
                throw new IOException("Can't copy directory (" + source.getAbsolutePath() + ") to non-directory: "
                        + destination.getAbsolutePath());
            }

            File files[] = source.listFiles(new WMFileNameFilter());
            for (int i = 0; i < files.length; i++) {
                copy(files[i], new File(destination, files[i].getName()), excludes);
            }
        } else if (source.isFile()) {
            if (destination.isDirectory()) {
                destination = new File(destination, source.getName());
            }

            InputStream in = new FileInputStream(source);
            OutputStream out = new FileOutputStream(destination);

            copy(in, out, true, true);

        } else {
            throw new IOException(
                    "Don't know how to copy " + source.getAbsolutePath() + "; it's neither a directory nor a file");
        }
    }

    public static void copy(File source, File destination, String includedPattern, String excludedPattern)
            throws IOException {
        List<String> includedPatterns = null, excludedPatterns = null;
        if (includedPattern != null) {
            includedPatterns = new ArrayList();
            includedPatterns.add(includedPattern);
        }
        if (excludedPattern != null) {
            excludedPatterns = new ArrayList();
            excludedPatterns.add(excludedPattern);
        }

        copy(source, destination, includedPatterns, excludedPatterns);
    }

    /**
     * Copy from: file to file, directory to directory, file to directory.
     *
     * @param source File object representing a file or directory to copy from.
     * @param destination File object representing the target; can only represent a file if the source is a file.
     * @param includedPatterns the ant-style path pattern to be included. Null means that all resources are included.
     * @param excludedPatterns the ant-style path pattern to be excluded. Null means that no resources are excluded.
     * @throws IOException
     */
    public static void copy(File source, File destination, List<String> includedPatterns,
            List<String> excludedPatterns) throws IOException {

        if (!source.exists()) {
            throw new IOException("Can't copy from non-existent file: " + source.getAbsolutePath());
        } else {
            PathMatcher matcher = new AntPathMatcher();

            boolean skip = false;
            if (includedPatterns != null) {
                for (String pattern : includedPatterns) {
                    if (matcher.match(pattern, source.getName())) {
                        break;
                    }
                }
            }

            if (excludedPatterns != null) {
                for (String pattern : excludedPatterns) {
                    if (matcher.match(pattern, source.getName())) {
                        skip = true;
                        break;
                    }
                }
            }

            if (skip) {
                return;
            }
        }

        if (source.isDirectory()) {
            if (!destination.exists()) {
                FileUtils.forceMkdir(destination);
            }
            if (!destination.isDirectory()) {
                throw new IOException("Can't copy directory (" + source.getAbsolutePath() + ") to non-directory: "
                        + destination.getAbsolutePath());
            }

            File files[] = source.listFiles(new WMFileNameFilter());

            for (int i = 0; i < files.length; i++) {
                copy(files[i], new File(destination, files[i].getName()), includedPatterns, excludedPatterns);
            }
        } else if (source.isFile()) {
            if (destination.isDirectory()) {
                destination = new File(destination, source.getName());
            }

            InputStream in = new FileInputStream(source);
            OutputStream out = new FileOutputStream(destination);

            copy(in, out, true, true);
        } else {
            throw new IOException(
                    "Don't know how to copy " + source.getAbsolutePath() + "; it's neither a directory nor a file");
        }
    }

    /**
     * Create a temporary directory, which will be deleted when the VM exits.
     *
     * @return The newly create temp directory
     * @throws IOException
     */
    public static File createTempDirectory() throws IOException {
        return createTempDirectory("fileUtils_createTempDirectory", null);
    }

    /**
     * Create a temporary directory, which will be deleted when the VM exits.
     *
     * @param prefix String used for directory name
     * @param suffix String used for directory name extension
     * @return The newly create temp directory
     * @throws IOException
     */
    public static File createTempDirectory(String prefix, String suffix) throws IOException {
        // prefix has to be at least 3 chars long
        StringBuilder prefixSB = new StringBuilder(prefix);
        while (prefixSB.length() < 3) {
            prefixSB.append("a");
        }
        prefix = prefixSB.toString();

        // we're seeing a bug on Windows where createTempFile() will fail; as
        // a workaround, we're trying a few times.
        File dir = null;
        IOException exception = null;
        for (int i = 0; i < 10; i++) {
            try {
                dir = File.createTempFile(prefix, suffix);
                break;
            } catch (IOException e) {
                exception = e;
            }
        }
        if (dir == null) {
            throw exception;
        }

        if (!dir.delete()) {
            throw new IOException("Couldn't delete: " + dir);
        } else if (!dir.mkdir()) {
            throw new IOException("Couldn't mkdir: " + dir);
        }
        return dir;
    }

    /**
     * Create a file at given location.
     */
    public static File createFile(String path) throws IOException {
        File file = new File(path);
        if (!file.exists())
            file.createNewFile();
        return file;
    }

    /**
     * Delete a directory or file; if a directory, delete its children recursively.
     *
     * @param dir
     * @throws IOException
     */
    public static void deleteRecursive(File dir) throws IOException {
        FileUtils.forceDelete(dir);
    }

    public static void cleanDirectorySilently(File dir) {
        try {
            FileUtils.cleanDirectory(dir);
        } catch (IllegalArgumentException | IOException e) {
            // ignore.
        }
    }

    public static void deleteDirectorySilently(File dir) {
        deleteDirectorySilently(dir, true);
    }

    public static String toString(InputStream is) {
        try {
            return org.apache.commons.io.IOUtils.toString(is, "UTF-8");
        } catch (IOException e) {
            throw new WMRuntimeException("Failed to get string from input stream", e);
        } finally {
            closeSilently(is);
        }
    }

    public static void deleteDirectorySilently(File dir, boolean noLogging) {
        if (dir == null) {
            return;
        }
        try {
            FileUtils.forceDelete(dir);
        } catch (IOException e) {
            if (!noLogging) {
                logger.warn("Failed to delete the directory {}", dir, e);
            }
        }
    }

    /**
     * Create intermediate directories so that the File represented by newFile can be created.
     *
     * @param newDir The directory that will be created; this method will ensure that the intermediate directories
     *        exist, and that this File is within the topLevel file.
     * @param topLevel This file should represent the top-level directory that files will not be created outside of.
     */
    public static void makeDirectories(File newDir, File topLevel) throws FileAccessException {

        if (newDir.exists()) {
            return;
        }

        if (!topLevel.exists()) {
            throw new FileAccessException(MessageResource.UTIL_FILEUTILS_PATHDNE, topLevel);
        } else if (!topLevel.isDirectory()) {
            throw new FileAccessException(MessageResource.UTIL_FILEUTILS_PATHNOTDIR, topLevel);
        }

        File absNewFile = newDir.getAbsoluteFile();
        IOUtils.makeDirectoriesRecurse(absNewFile, topLevel);
    }

    /**
     * Get all files (excluding directories) under dir.
     */
    public static Collection<File> getFiles(File indir) {
        if (!indir.isDirectory()) {
            throw new IllegalArgumentException("Expected directory as input");
        }
        Collection<File> rtn = new HashSet<File>();

        List<File> dirs = new ArrayList<File>();
        dirs.add(indir);

        while (!dirs.isEmpty()) {

            File dir = dirs.remove(0);

            String[] files = dir.list();
            for (String s : files) {
                File f = new File(dir, s);
                if (f.isDirectory()) {
                    dirs.add(f);
                } else {
                    rtn.add(f);
                }
            }
        }

        return rtn;
    }

    private static void makeDirectoriesRecurse(File dir, File topLevel) throws FileAccessException {

        // if we're at the topLevel end recursion
        if (dir.equals(topLevel)) {
            return;
        }

        // if we're at the filesystem root, error
        for (File root : File.listRoots()) {
            if (dir.equals(root)) {
                throw new FileAccessException(MessageResource.UTIL_FILEUTILS_REACHEDROOT, root, topLevel);
            }
        }

        // make & check parent directories
        makeDirectoriesRecurse(dir.getParentFile(), topLevel);

        // make this directory
        if (!dir.exists()) {
            dir.mkdir();
        }
    }

    /**
     * Touch a file (see touch(1)). If the file doesn't exist, create it as an empty file. If it does exist, update its
     * modification time.
     *
     * @param f The File.
     * @throws IOException
     */
    public static void touch(File f) throws IOException {

        if (!f.exists()) {
            FileWriter fw = new FileWriter(f);
            fw.close();
        } else {
            f.setLastModified(System.currentTimeMillis());
        }
    }

    /**
     * Return true iff we should exclude file, based on DEFAULT_EXCLUSION. The filename of file must be an exact match,
     * so this is more suitable for use with directories.
     */
    public static boolean excludeByExactMatch(File file) {

        return DEFAULT_EXCLUSION.contains(file.getName());
    }

    public static void closeXmlReaderSilently(XMLStreamReader reader) {
        if (reader != null) {
            try {
                reader.close();
            } catch (Exception exc) {
            }
        }
    }

    public static void closeSilently(AutoCloseable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (Exception exc) {
            }
        }
    }

    public static void closeByLogging(AutoCloseable e) {
        if (e != null) {
            try {
                e.close();
            } catch (Exception exc) {
                logger.warn("Failed to close the stream", exc);
            }
        }
    }

    static class WMFileNameFilter implements FilenameFilter {
        @Override
        public boolean accept(File dir, String name) {
            return name.indexOf("#") == -1 && name.indexOf("~") == -1;
        }
    }
}