net.rptools.lib.FileUtil.java Source code

Java tutorial

Introduction

Here is the source code for net.rptools.lib.FileUtil.java

Source

/*
 * 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 net.rptools.lib;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import com.thoughtworks.xstream.XStream;

public class FileUtil {
    private static final Logger log = Logger.getLogger(FileUtil.class);

    /**
     * Can't use this for String objects yet as it's Java 6+ and we're trying to be Java 5 compatible. But soon...
     */
    public static final Charset UTF_8 = Charset.forName("UTF-8");

    /**
     * Reads the entire content of the given file into a byte array.
     * 
     * @deprecated use {@link FileUtils#readFileToByteArray(File)} instead.
     * @param file
     * @return byte contents of the file
     * @throws IOException
     */
    @Deprecated
    public static byte[] loadFile(File file) throws IOException {
        return FileUtils.readFileToByteArray(file);
    }

    /**
     * Reads the entire content of the given file into a byte array.
     * 
     * @deprecated use {@link FileUtils#readFileToByteArray(File)} instead.
     * @param file
     * @return
     * @throws IOException
     */
    @Deprecated
    public static byte[] getBytes(File file) throws IOException {
        return FileUtils.readFileToByteArray(file);
    }

    public static Object objFromResource(String res) throws IOException {
        XStream xs = new XStream();
        InputStream is = null;
        try {
            is = FileUtil.class.getClassLoader().getResourceAsStream(res);
            return xs.fromXML(new InputStreamReader(is, "UTF-8"));
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    public static byte[] loadResource(String resource) throws IOException {
        InputStream is = null;
        try {
            is = FileUtil.class.getClassLoader().getResourceAsStream(resource);
            if (is == null) {
                throw new IOException("Resource \"" + resource + "\" cannot be opened as stream.");
            }
            return IOUtils.toByteArray(new InputStreamReader(is, "UTF-8"));
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    @SuppressWarnings("unchecked")
    public static List<String> getLines(File file) throws IOException {
        List<String> list;
        FileReader fr = new FileReader(file);
        try {
            list = IOUtils.readLines(fr);
        } finally {
            fr.close();
        }
        return list;
    }

    public static void saveResource(String resource, File destDir) throws IOException {
        int index = resource.lastIndexOf('/');
        String filename = index >= 0 ? resource.substring(index + 1) : resource;
        saveResource(resource, destDir, filename);
    }

    public static void saveResource(String resource, File destDir, String filename) throws IOException {
        File outFilename = new File(destDir, filename);
        InputStream inStream = null;
        OutputStream outStream = null;
        try {
            inStream = FileUtil.class.getClassLoader().getResourceAsStream(resource);
            outStream = new BufferedOutputStream(new FileOutputStream(outFilename));
            IOUtils.copy(inStream, outStream);
        } finally {
            IOUtils.closeQuietly(inStream);
            IOUtils.closeQuietly(outStream);
        }
    }

    private static final Pattern TRIM_EXTENSION_PATTERN = Pattern.compile("^(.*)\\.([^\\.]*)$");

    public static String getNameWithoutExtension(File file) {
        return getNameWithoutExtension(file.getName());
    }

    public static String getNameWithoutExtension(String filename) {
        if (filename == null) {
            return null;
        }
        Matcher matcher = TRIM_EXTENSION_PATTERN.matcher(filename);
        if (!matcher.matches()) {
            return filename;
        }
        return matcher.group(1);
    }

    public static String getNameWithoutExtension(URL url) {
        String file = url.getFile();
        try {
            file = url.toURI().getPath();
            //         int beginning = file.lastIndexOf(File.separatorChar); // Don't need to strip the path since the File() constructor will take care of that
            //         file = file.substring(beginning < 0 ? 0 : beginning + 1);
        } catch (URISyntaxException e) {
            // If the conversion doesn't work, ignore it and use the original file name.
        }
        return getNameWithoutExtension(new File(file));
    }

    public static byte[] getBytes(URL url) throws IOException {
        InputStream is = null;
        try {
            is = url.openStream();
            return IOUtils.toByteArray(is);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    /**
     * Returns the data in a file using the UTF-8 character encoding. The platform default may not be appropriate since
     * the file could've been produced on a different platform. The only safe thing to do is use UTF-8 and hope that
     * everyone uses it by default when they edit text files. :-/
     * 
     * @deprecated This is not in use, and {@link IOUtils#toCharArray(InputStream, String)} should be used directly
     *             anyways
     */
    @Deprecated
    public static String getString(InputStream is) throws IOException {
        if (is == null)
            throw new IllegalArgumentException("InputStream cannot be null");
        return IOUtils.toString(is, "UTF-8");
    }

    /**
     * Reads the given file as UTF-8 bytes and returns the contents as a standard Java string.
     * 
     * @deprecated This is not in use, and {@link FileUtils#readFileToString(File, String)} should be used directly
     *             anyways
     * @param file
     *            file to retrieve contents from
     * @return String representing the contents
     * @throws IOException
     */
    @Deprecated
    public static String getString(File file) throws IOException {
        if (file == null) {
            throw new IllegalArgumentException("file cannot be null");
        }
        return FileUtils.readFileToString(file, "UTF-8");
    }

    /**
     * Given an InputStream this method tries to figure out what the content type might be.
     * 
     * @param in
     *            the InputStream to check
     * @return a <code>String</code> representing the content type name
     */
    public static String getContentType(InputStream in) {
        String type = "";
        try {
            type = URLConnection.guessContentTypeFromStream(in);
            if (log.isDebugEnabled())
                log.debug("result from guessContentTypeFromStream() is " + type);
        } catch (IOException e) {
        }
        return type;
    }

    /**
     * Given a URL this method tries to figure out what the content type might be based only on the filename extension.
     * 
     * @param url
     *            the URL to check
     * @return a <code>String</code> representing the content type name
     */
    public static String getContentType(URL url) {
        String type = "";
        type = URLConnection.guessContentTypeFromName(url.getPath());
        if (log.isDebugEnabled())
            log.debug("result from guessContentTypeFromName(" + url.getPath() + ") is " + type);
        return type;
    }

    /**
     * Given a <code>File</code> this method tries to figure out what the content type might be based only on the
     * filename extension.
     * 
     * @param file
     *            the File to check
     * @return a <code>String</code> representing the content type name
     */
    public static String getContentType(File file) {
        try {
            return getContentType(file.toURI().toURL());
        } catch (MalformedURLException e) {
            return null;
        }
    }

    /**
        * Returns a {@link BufferedReader from the given <code>File</code> object.  The contents
        * of the file are expected to be UTF-8.
        * 
        * @param file the input data source
        * @return a String representing the data
        * @throws IOException
        */
    public static BufferedReader getFileAsReader(File file) throws IOException {
        return new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
    }

    /**
     * Given a URL this method determines the content type of the URL (if possible) and then returns a Reader with the
     * appropriate character encoding.
     * 
     * @param url
     *            the source of the data stream
     * @return String representing the data
     * @throws IOException
     */
    public static Reader getURLAsReader(URL url) throws IOException {
        InputStreamReader isr = null;
        URLConnection conn = null;
        // We're assuming character here, but it could be bytes.  Perhaps we should
        // check the MIME type returned by the network server?
        conn = url.openConnection();
        if (log.isDebugEnabled()) {
            String type = URLConnection.guessContentTypeFromName(url.getPath());
            log.debug("result from guessContentTypeFromName(" + url.getPath() + ") is " + type);
            type = getContentType(conn.getInputStream());
            // Now make a guess and change 'encoding' to match the content type...
        }
        isr = new InputStreamReader(conn.getInputStream(), "UTF-8");
        return isr;
    }

    public static InputStream getFileAsInputStream(File file) throws IOException {
        return getURLAsInputStream(file.toURI().toURL());
    }

    /**
     * Given a URL this method determines the content type of the URL (if possible) and then returns an InputStream.
     * 
     * @param url
     *            the source of the data stream
     * @return InputStream representing the data
     * @throws IOException
     */
    public static InputStream getURLAsInputStream(URL url) throws IOException {
        InputStream is = null;
        URLConnection conn = null;
        // We're assuming character here, but it could be bytes.  Perhaps we should
        // check the MIME type returned by the network server?
        conn = url.openConnection();
        if (log.isDebugEnabled()) {
            String type = URLConnection.guessContentTypeFromName(url.getPath());
            log.debug("result from guessContentTypeFromName(" + url.getPath() + ") is " + type);
            type = getContentType(conn.getInputStream());
            log.debug("result from getContentType(" + url.getPath() + ") is " + type);
        }
        is = conn.getInputStream();
        return is;
    }

    /**
     * Writes given bytes to file indicated by <code>file</code>. This method will overwrite any existing file at that
     * location, and will create any sub-directories required.
     * 
     * @deprecated use {@link FileUtils#writeByteArrayToFile(File, byte[])} instead.
     * @param file
     * @param data
     * @throws IOException
     */
    @Deprecated
    public static void writeBytes(File file, byte[] data) throws IOException {
        FileUtils.writeByteArrayToFile(file, data);
    }

    /**
     * Copies <code>sourceFile</code> to <code>destFile</code> overwriting as required, and <b>not</b> preserving the
     * source file's last modified time. The destination directory is created if it does not exist, and if the
     * destination file exists, it is overwritten.
     * 
     * @param sourceFile
     * @param destFile
     * @throws IOException
     */
    public static void copyFile(File sourceFile, File destFile) throws IOException {
        FileUtils.copyFile(sourceFile, destFile, false);
    }

    /**
     * Unzips the indicated file from the <code>classpathFile</code> location into the indicated <code>destDir</code>.
     * 
     * @param classpathFile
     * @param destDir
     * @throws IOException
     */
    public static void unzip(String classpathFile, File destDir) throws IOException {
        try {
            unzip(FileUtil.class.getClassLoader().getResource(classpathFile), destDir);
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

    /**
     * Loads the given {@link URL}, and unzips the URL's contents into the given <code>destDir</code>.
     * 
     * @param url
     * @param destDir
     * @throws IOException
     */
    public static void unzip(URL url, File destDir) throws IOException {
        if (url == null)
            throw new IOException("URL cannot be null");

        InputStream is = url.openStream();
        ZipInputStream zis = null;
        try {
            zis = new ZipInputStream(new BufferedInputStream(is));
            unzip(zis, destDir);
        } finally {
            IOUtils.closeQuietly(zis);
        }
    }

    public static void unzip(ZipInputStream in, File destDir) throws IOException {
        if (in == null)
            throw new IOException("input stream cannot be null");

        // Prepare destination
        destDir.mkdirs();
        File absDestDir = destDir.getAbsoluteFile();

        // Pull out the files
        OutputStream out = null;
        ZipEntry entry = null;
        try {
            while ((entry = in.getNextEntry()) != null) {
                if (entry.isDirectory())
                    continue;

                // Prepare file destination
                File entryFile = new File(absDestDir, entry.getName());
                entryFile.getParentFile().mkdirs();

                out = new FileOutputStream(entryFile);
                IOUtils.copy(in, out);
                IOUtils.closeQuietly(out);
                in.closeEntry();
            }
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    public static void unzipFile(File sourceFile, File destDir) throws IOException {
        if (!sourceFile.exists())
            throw new IOException("source file does not exist: " + sourceFile);

        ZipFile zipFile = null;
        InputStream is = null;
        OutputStream os = null;
        try {
            zipFile = new ZipFile(sourceFile);
            Enumeration<? extends ZipEntry> entries = zipFile.entries();

            while (entries.hasMoreElements()) {
                ZipEntry entry = entries.nextElement();
                if (entry.isDirectory())
                    continue;

                File file = new File(destDir, entry.getName());
                String path = file.getAbsolutePath();
                file.getParentFile().mkdirs();

                //System.out.println("Writing file: " + path);
                is = zipFile.getInputStream(entry);
                os = new BufferedOutputStream(new FileOutputStream(path));
                copyWithClose(is, os);
                IOUtils.closeQuietly(is);
                IOUtils.closeQuietly(os);
            }
        } finally {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(os);
            try {
                if (zipFile != null)
                    zipFile.close();
            } catch (Exception e) {
            }
        }
    }

    /**
     * Copies all bytes from InputStream to OutputStream without closing either stream.
     * 
     * @deprecated not in use. Use {@link IOUtils#copy(InputStream, OutputStream)} instead.
     * @param is
     * @param os
     * @throws IOException
     */
    @Deprecated
    public static void copyWithoutClose(InputStream is, OutputStream os) throws IOException {
        IOUtils.copy(is, os);
    }

    /**
     * Copies all bytes from InputStream to OutputStream, and close both streams before returning.
     * 
     * @param is
     *            input stream to read data from.
     * @param os
     *            output stream to write data to.
     * @throws IOException
     */
    public static void copyWithClose(InputStream is, OutputStream os) throws IOException {
        try {
            IOUtils.copy(is, os);
        } finally {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(os);
        }
    }

    /**
     * Recursively deletes all files and/or directories that have been modified longer than <code>daysOld</code> days
     * ago. Note that this will recursively examine a directory, and only deletes those items that are too old.
     * 
     * @param file
     *            the file or directory to recursively check and possibly delete
     * @param daysOld
     *            number of days old a file or directory can be before it is considered for deletion
     * @throws IOException
     *             if something goes wrong
     */
    public static void delete(File file, int daysOld) throws IOException {
        Calendar olderThan = new GregorianCalendar();
        olderThan.add(Calendar.DATE, -daysOld);

        boolean shouldDelete = new Date(file.lastModified()).before(olderThan.getTime());

        if (file.isDirectory()) {
            // Wipe the contents first
            for (File currfile : file.listFiles()) {
                if (".".equals(currfile.getName()) || "..".equals(currfile.getName()))
                    continue;
                delete(currfile, daysOld);
            }
        }
        if (shouldDelete)
            file.delete();
    }

    /**
     * Recursively deletes the given file or directory
     * 
     * @see {@link FileUtils#deleteQuietly(File)}
     * @param file
     *            to recursively delete
     */
    public static void delete(File file) {
        FileUtils.deleteQuietly(file);
    }

    /**
     * Replace invalid File name characters, useful for token Save function to
     * replace the : in Lib tokens.
     * 
     * @author Jamz
     * @since 1.4.0.2
     * 
     * @param fileName
     * @return
     */
    public static String stripInvalidCharacters(String fileName) {
        return fileName = fileName.replaceAll("[^\\w\\s.,-]", "_");
    }
}