fm.last.commons.io.LastFileUtils.java Source code

Java tutorial

Introduction

Here is the source code for fm.last.commons.io.LastFileUtils.java

Source

/*
 * Copyright 2009 Last.fm
 *
 *  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 fm.last.commons.io;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.util.Arrays;
import java.util.List;

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

/**
 * File related utilities.
 */
public class LastFileUtils {

    private static Logger log = Logger.getLogger(LastFileUtils.class);

    /**
     * Appends the passed string to the passed file.
     * 
     * @param file File to append string to (will be created if it does not exist).
     * @param string String to append.
     * @throws IOException If an error occurs appending the string to the file.
     */
    public static void appendStringToFile(File file, String string) throws IOException {
        BufferedWriter writer = new BufferedWriter(new FileWriter(file, true));
        writer.write(string);
        writer.close();
    }

    /**
     * Appends the passed files (in order) to the destination.
     * 
     * @param destination Destination file.
     * @param files Array of files to be appended to the destination file.
     * @throws IOException If an error occurs appending the files.
     */
    public static void appendFiles(File destination, File... files) throws IOException {
        appendFiles(destination, Arrays.asList(files));
    }

    /**
     * Appends the passed files (in list order) to the destination.
     * 
     * @param destination Destination file.
     * @param files List of files to be appended to the destination file.
     * @throws IOException If an error occurs appending the files.
     */
    public static void appendFiles(File destination, List<File> files) throws IOException {
        FileUtils.copyFile(files.get(0), destination);
        FileOutputStream fos = new FileOutputStream(destination, true);
        for (int i = 1; i < files.size(); i++) {
            FileInputStream fis = new FileInputStream(files.get(i));
            IOUtils.copy(fis, fos);
            IOUtils.closeQuietly(fis);
        }
        IOUtils.closeQuietly(fos);
    }

    /**
     * Reads the last bytes from the end of the passed file as a String.
     * 
     * @param file File to read from.
     * @param bytes Number of bytes from end of file to read.
     * @return The end content of the file as a String.
     * @throws IOException If the file could not be opened or read.
     */
    public static String tail(File file, long bytes) throws IOException {
        RandomAccessFile raFile = null;
        StringBuffer tail = new StringBuffer();
        try {
            raFile = new RandomAccessFile(file, "r");
            long length = raFile.length();
            if (bytes >= length) {
                return FileUtils.readFileToString(file);
            } else {
                raFile.seek(length - bytes);
                tail = new StringBuffer((int) bytes);
                String line = raFile.readLine();
                while (line != null) {
                    tail.append(line);
                    line = raFile.readLine();
                    if (line != null) { // there is another line coming, so add line break
                        tail.append("\n");
                    }
                }
            }
        } finally {
            LastIoUtils.closeQuietly(raFile);
        }
        return tail.toString();
    }

    /**
     * Searches for a file on local filesytem, classpath etc.
     * 
     * @param fileName Name of file to find.
     * @param classToLoadFrom Class to use as a base for finding the file via it's classloader, if necessary.
     * @return The file if found on the file system.
     * @throws FileNotFoundException If the File could not be found.
     */
    public static File getFile(String fileName, Class<?> classToLoadFrom) throws FileNotFoundException {
        File file = new File(fileName); // first try the path directly
        if (!file.exists()) {
            URL fileURL = classToLoadFrom.getResource(fileName);// next try the class's classpath
            if (fileURL == null) {
                fileURL = classToLoadFrom.getClassLoader().getResource(fileName);// next try the class' classloader's classpath
                if (fileURL == null) {
                    fileURL = ClassLoader.getSystemClassLoader().getResource(fileName); // finally try the system classloader's
                    // classpath
                    if (fileURL == null) {
                        throw new FileNotFoundException(
                                "Could not find " + fileName + " on path, classpath " + "or system classpath");
                    }
                }
            }
            file = new File(fileURL.getFile());
        }
        log.debug("Path to file located is " + file.getAbsolutePath());
        return file;
    }

    /**
     * Writes the contents of the passed input stream to the passed file and closes the InputStream when done.
     * 
     * @param inputStream Input stream to write to file.
     * @param file The file to write to.
     * @throws IOException If an error occurs writing the InputStream to the file.
     */
    public static void writeToFile(InputStream inputStream, File file) throws IOException {
        writeToFile(inputStream, file, true);
    }

    /**
     * Writes the contents of the passed input stream to the passed file and closes the InputStream when done.
     * 
     * @param inputStream Input stream to write to file.
     * @param file The file to write to.
     * @param makeDirs Whether to create the files parent dir(s) or not.
     * @throws IOException If an error occurs writing the InputStream to the file.
     */
    public static void writeToFile(InputStream inputStream, File file, boolean makeDirs) throws IOException {
        if (makeDirs && file.getParentFile() != null && !file.getParentFile().exists()) {
            if (!file.getParentFile().mkdirs()) {
                throw new IOException("Error creating '" + file.getParentFile().getAbsolutePath() + "'");
            }
        }
        BufferedOutputStream outputStream = null;
        try {
            outputStream = new BufferedOutputStream(new FileOutputStream(file));
            byte[] inBuffer = new byte[32 * 1024];
            int bytesRead = 0;
            while ((bytesRead = inputStream.read(inBuffer)) != -1) {
                outputStream.write(inBuffer, 0, bytesRead);
            }
        } finally {
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outputStream);
        }
    }

    /**
     * Moves a file "safely" - first copies it to the destination with ".part" appended to the filename, and then renames
     * it. This is useful for copying files to locations where files with certain extensions are processed. The rename
     * step should be a lot quicker than the copying step, preventing the file from being processed before it is fully
     * copied.
     * 
     * @param srcFile Source file.
     * @param destFile Destination file.
     * @throws IOException If an error occurrs moving the file.
     */
    public static void moveFileSafely(File srcFile, File destFile) throws IOException {
        File partFile = new File(destFile.getParentFile(), destFile.getName() + ".part");
        FileUtils.moveFile(srcFile, partFile);
        if (!partFile.renameTo(destFile)) {
            throw new IOException(
                    "Error renaming " + partFile.getAbsolutePath() + " to " + destFile.getAbsolutePath());
        }
    }

    /**
     * Moves a file "safely" to a directory - first copies it to the destination with ".part" appended to the filename,
     * and then renames it. This is useful for copying files to locations where files with certain extensions are
     * processed. The rename step should be a lot quicker than the copying step, preventing the file from being processed
     * before it is fully copied.
     * 
     * @param srcFile Source file.
     * @param destDir Destination directory.
     * @throws IOException If an error occurs moving the file.
     */
    public static void moveFileToDirectorySafely(File srcFile, File destDir, boolean createDestDir)
            throws IOException {
        if (destDir == null) {
            throw new NullPointerException("Destdir must not be null");
        }
        if (!destDir.exists() && createDestDir) {
            if (!destDir.mkdirs()) {
                throw new IOException("Could not create " + destDir.getAbsolutePath());
            }
        }
        if (!destDir.exists()) {
            throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist");
        }
        moveFileSafely(srcFile, new File(destDir, srcFile.getName()));
    }

    public static boolean canRead(File file) {
        return file != null && file.exists() && file.canRead();
    }

}