All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.util.io.FileUtils Maven / Gradle / Ivy

There is a newer version: 8.0.0-JDK17-M7
Show newest version
/*
 * Copyright (c) 2022 Contributors to the Eclipse Foundation
 * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.enterprise.util.io;

import com.sun.enterprise.universal.i18n.LocalStringsImpl;
import com.sun.enterprise.universal.io.SmartFile;
import com.sun.enterprise.util.CULoggerInfo;
import com.sun.enterprise.util.OS;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.Writer;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
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.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;

import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.TRACE;
import static java.lang.System.Logger.Level.WARNING;


public class FileUtils {
    /** Current user's home directory resolved from the system property user.home */
    public static final File USER_HOME = new File(System.getProperty("user.home"));

    private static final Logger LOG = System.getLogger(FileUtils.class.getName());
    private final static LocalStringsImpl messages = new LocalStringsImpl(FileUtils.class);

    /**
     * The method, java.io.File.getParentFile() does not necessarily do what
     * you would think it does.  What it really does is to simply chop off the
     * final element in the path and return what is left-over.  E.g.
     * if the file is /foo/.  then the "parent" that is returned is /foo
     * which is probably not what you expected.
     * This method really returns the parent directory - or null if there is none.
     * @param f
     * @return
     */
    public static File getParentFile(File f) {
        if (f == null) {
            return null;
        }

        return SmartFile.sanitize(f).getParentFile();
    }

    /**
     * Result: existing writable directory given in parameter OR {@link IllegalStateException}.
     *
     * @param dir
     * @throws IllegalStateException The exception should not be catched, because it means that
     *             the client can have unpredictable issues.
     */
    public static void ensureWritableDir(File dir) {
        if (dir.exists()) {
            if (!dir.isDirectory()) {
                throw new IllegalStateException("The configured temporary directory is not a directory: " + dir);
            }
            if (!dir.canWrite()) {
                throw new IllegalStateException("The configured temporary directory is not writeable: " + dir);
            }
            return;
        }
        if (dir.mkdirs()) {
            LOG.log(DEBUG, "The directory {0} has been created.", dir);
            return;
        }
        // just note: mkdirs maybe created part of the path, but we don't care here.
        throw new IllegalStateException("The configured directory does not exist and could not be created: " + dir);
    }

    /**
     * Wrapper for File.mkdirs
     * This version will return true if the directory exists when the method returns.
     * Unlike File.mkdirs which returns false if the directory already exists.
     * @param f The file pointing to the directory to be created
     * @return
     */
    public static boolean mkdirsMaybe(File f) {
        return f != null && (f.isDirectory() || f.mkdirs());
    }

    /**
     * Wrapper for File.delete
     * This version will return true if the file does not exist when the method returns.
     * Unlike File.delete which returns false if the file does not exist.
     * @param f The file to be deleted
     * @return
     */
    public static boolean deleteFileMaybe(File f) {
        return f != null && (!f.exists() || f.delete());
    }

    /*
    * Wrapper for File.listFiles
    * Guaranteed to return an array in all cases.
    * File.listFiles() returns either null or an empty array.  This is annoying and results in harder
    * than neccessry to read code -- i.e. there are 3 results possible:
    * an array with files in it
    * an empty array
    * a null
    */
    public static File[] listFiles(File f) {
        try {
            File[] files = f.listFiles();

            if(files != null) {
                return files;
            }
        }
        catch(Exception e) {
            // fall through
        }

        return new File[0];
    }

    public static File[] listFiles(File f, FileFilter ff) {
        try {
            File[] files = f.listFiles(ff);

            if(files != null) {
                return files;
            }
        }
        catch(Exception e) {
            // fall through
        }

        return new File[0];
    }

    public static File[] listFiles(File f, FilenameFilter fnf) {
        try {
            File[] files = f.listFiles(fnf);

            if(files != null) {
                return files;
            }
        }
        catch(Exception e) {
            // fall through
        }

        return new File[0];
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean safeIsDirectory(File f) {
        if (f == null || !f.exists() || !f.isDirectory()) {
            return false;
        }

        return true;
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean safeIsRealDirectory(String s) {
        return safeIsRealDirectory(new File(s));
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean safeIsRealDirectory(File f) {
        if (safeIsDirectory(f) == false) {
            return false;
        }

        // these 2 values while be different for symbolic links
        String canonical = safeGetCanonicalPath(f);
        String absolute = f.getAbsolutePath();

        if (canonical.equals(absolute)) {
            return true;
        }

        /* Bug 4715043 -- WHOA -- Bug Obscura!!
           * In Windows, if you create the File object with, say, "d:/foo", then the
           * absolute path will be "d:\foo" and the canonical path will be "D:\foo"
           * and they won't match!!!
           **/
        if (OS.isWindows() && canonical.equalsIgnoreCase(absolute)) {
            return true;
        }

        return false;
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean safeIsDirectory(String s) {
        return safeIsDirectory(new File(s));
    }

    ///////////////////////////////////////////////////////////////////////////

    public static String safeGetCanonicalPath(File f) {
        if (f == null) {
            return null;
        }

        try {
            return f.getCanonicalPath();
        }
        catch (IOException e) {
            return f.getAbsolutePath();
        }
    }

    ///////////////////////////////////////////////////////////////////////////

    public static File safeGetCanonicalFile(File f) {
        if (f == null) {
            return null;
        }

        try {
            return f.getCanonicalFile();
        }
        catch (IOException e) {
            return f.getAbsoluteFile();
        }
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean hasExtension(String filename, String ext) {
        if (filename == null || filename.length() <= 0) {
            return false;
        }

        return filename.endsWith(ext);
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean hasExtension(File f, String ext) {
        if (f == null || !f.exists()) {
            return false;
        }

        return f.getName().endsWith(ext);
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean hasExtensionIgnoreCase(String filename, String ext) {
        if (filename == null || filename.length() <= 0) {
            return false;
        }

        return filename.toLowerCase(Locale.ENGLISH).endsWith(ext.toLowerCase(Locale.ENGLISH));
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean hasExtensionIgnoreCase(File f, String ext) {
        if (f == null || !f.exists()) {
            return false;
        }

        return f.getName().toLowerCase(Locale.ENGLISH).endsWith(ext.toLowerCase(Locale.ENGLISH));
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean isLegalFilename(String filename) {
        if (!isValidString(filename)) {
            return false;
        }

        for (char element : ILLEGAL_FILENAME_CHARS) {
            if (filename.indexOf(element) >= 0) {
                return false;
            }
        }

        return true;
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean isFriendlyFilename(String filename) {
        if (!isValidString(filename)) {
            return false;
        }

        if (filename.indexOf(BLANK) >= 0 || filename.indexOf(DOT) >= 0) {
            return false;
        }

        return isLegalFilename(filename);
    }

    ///////////////////////////////////////////////////////////////////////////

    public static String makeLegalFilename(String filename) {
        if (isLegalFilename(filename)) {
            return filename;
        }

        // let's use "__" to replace "/" and "\" (on Windows) so less chance
        // to collide with the actual name when reverting
        filename = filename.replaceAll("[/" + Pattern.quote("\\") + "]", "__");

        for (char element : ILLEGAL_FILENAME_CHARS) {
            filename = filename.replace(element, REPLACEMENT_CHAR);
        }

        return filename;
    }

    ///////////////////////////////////////////////////////////////////////////

    public static String makeLegalNoBlankFileName(String filename)
    {
        return  makeLegalFilename(filename).replace(
            BLANK, REPLACEMENT_CHAR);
    }


    ///////////////////////////////////////////////////////////////////////////
    public static String makeFriendlyFilename(String filename) {
        if (isFriendlyFilename(filename)) {
            return filename;
        }

        String ret = makeLegalFilename(filename).replace(BLANK, REPLACEMENT_CHAR);
        ret = ret.replace(DOT, REPLACEMENT_CHAR);
        return ret;
    }

    ///////////////////////////////////////////////////////////////////////////

    public static String makeFriendlyFilenameNoExtension(String filename) {
        int index = filename.lastIndexOf('.');

        if (index > 0) {
            filename = filename.substring(0, index);
        }

        return (makeFriendlyFilename(filename));
    }

    ///////////////////////////////////////////////////////////////////////////

    public static String makeFriendlyFilenameExtension(String filename) {
        if (filename == null) {
            return null;
        }

        filename = makeLegalNoBlankFileName(filename);

        String extension = "";
        if (filename.endsWith(".ear")) {
            filename = filename.substring(0, filename.indexOf(".ear"));
            extension = "_ear";
        } else if (filename.endsWith(".war")) {
            filename = filename.substring(0, filename.indexOf(".war"));
            extension = "_war";
        } else if (filename.endsWith(".jar")) {
            filename = filename.substring(0, filename.indexOf(".jar"));
            extension = "_jar";
        } else if (filename.endsWith(".rar")) {
            filename = filename.substring(0, filename.indexOf(".rar"));
            extension = "_rar";
        }
        return filename + extension;
    }

    public static String revertFriendlyFilenameExtension(String filename) {
        if (filename == null ||
                !(filename.endsWith("_ear") || filename.endsWith("_war") ||
                        filename.endsWith("_jar") || filename.endsWith("_rar"))) {
            return filename;
        }

        String extension = "";
        if (filename.endsWith("_ear")) {
            filename = filename.substring(0, filename.indexOf("_ear"));
            extension = ".ear";
        } else if (filename.endsWith("_war")) {
            filename = filename.substring(0, filename.indexOf("_war"));
            extension = ".war";
        } else if (filename.endsWith("_jar")) {
            filename = filename.substring(0, filename.indexOf("_jar"));
            extension = ".jar";
        } else if (filename.endsWith("_rar")) {
            filename = filename.substring(0, filename.indexOf("_rar"));
            extension = ".rar";
        }
        return filename + extension;
    }

    public static String revertFriendlyFilename(String filename) {

        //first, revert the file extension
        String name = revertFriendlyFilenameExtension(filename);

        //then, revert the rest of the string
        return name.replaceAll("__", "/");
    }

    /////////////////////////////////////////////////////////

    public static void liquidate(File parent) {
        whack(parent);
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean isJar(String filename)
    {
        return hasExtension(filename, ".jar");
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean isZip(String filename)
    {
        return hasExtensionIgnoreCase(filename, ".zip");
    }

    ///////////////////////////////////////////////////////////////////////////

    public static boolean isJar(File f)
    {
        return hasExtension(f, ".jar");
    }

    ///////////////////////////////////////////////////////////////////////////
    public static boolean isZip(File f)
    {
        return hasExtensionIgnoreCase(f, ".zip");
    }

    /**
     * Deletes a directory and its contents.
     * 

* If this method encounters a symbolic link in the subtree below "parent" * then it deletes the link but not any of the files pointed to by the link. * Note that whack will delete files if a symbolic link appears in the * path above the specified parent directory in the path. * * @param parent the File at the top of the subtree to delete * @return success or failure of deleting the directory */ public static boolean whack(File parent) { return whack(parent, null); } /** * Deletes a directory and its contents. *

* If this method encounters a symbolic link in the subtree below "parent" * then it deletes the link but not any of the files pointed to by the link. * Note that whack will delete files if a symbolic link appears in the * path above the specified parent directory in the path. * * @param parent the File at the top of the subtree to delete * @return success or failure of deleting the directory */ public static boolean whack(File parent, Collection undeletedFiles) { try { /* *Resolve any links up-stream from this parent directory and *then whack the resulting resolved directory. */ return whackResolvedDirectory(parent.getCanonicalFile(), undeletedFiles); } catch (IOException ioe) { LOG.log(Level.ERROR, "Could not recursively delete the directory " + parent, ioe); return false; } } /** * Deletes a directory and its contents. *

* The whackResolvedDirectory method is invoked with a File argument * in which any upstream file system links have already been resolved. * This method will treate Any file passed in that does not have the same * absolute and canonical path - as evaluated in safeIsRealDirectory - * as a link and will delete the link without deleting any files in the * linked directory. * * @param parent the File at the top of the subtree to delete * @return success or failure of deleting the directory */ private static boolean whackResolvedDirectory(File parent, Collection undeletedFiles) { /* *Do not recursively delete the contents if the current parent *is a symbolic link. */ if (safeIsRealDirectory(parent)) { File[] kids = listFiles(parent); for (File f : kids) { if (f.isDirectory()) { whackResolvedDirectory(f, undeletedFiles); } else if (!deleteFile(f) && undeletedFiles != null) { undeletedFiles.add(f); } } } /* *Delete the directory or symbolic link. */ return deleteFile(parent); } /** * Delete a file. If impossible to delete then try to delete it when the JVM exits. * E.g. when Windows is using a jar in the current JVM -- you can not delete the jar until * the JVM dies. * @param f file to delete */ public static void deleteFileNowOrLater(File f) { if(!deleteFile(f)) { f.deleteOnExit(); } } /** * Delete a file. Will retry every ten milliseconds for five seconds, doing a * gc after each second. * * @param f file to delete * @return boolean indicating success or failure of the deletion atttempt; returns true if file is absent */ public static boolean deleteFileWithWaitLoop(File f) { return internalDeleteFile(f, true); } /** * Delete a file. If on Windows and the delete fails, run the gc and retry the deletion. * * @param f file to delete * @return boolean indicating success or failure of the deletion atttempt; returns true if file is absent */ public static boolean deleteFile(File f) { return internalDeleteFile(f, false); } /** * Delete a file. If on Windows and the delete fails, run the gc and retry the deletion. * * @param f file to delete * @return boolean indicating success or failure of the deletion atttempt; returns true if file is absent */ private static boolean internalDeleteFile(File f, boolean doWaitLoop) { /* *The operation succeeds immediately if the file is deleted *successfully. On systems that support symbolic links, the file *will be reported as non-existent if the file is a sym link to a *non-existent directory. In that case invoke delete to remove *the link before checking for existence, since File.exists on *a symlink checks for the existence of the linked-to directory or *file rather than of the link itself. */ if (!doWaitLoop) { if (f.delete()) { return true; } } else { DeleteFileWork work = new DeleteFileWork(f); doWithRetry(work); if (work.workComplete()) { return true; } } String filePath = f.getAbsolutePath(); /* *The deletion failed. This could be simply because the file *does not exist. In that case, log an appropriate message and *return. */ if (!f.exists()) { LOG.log(TRACE, "Attempt to delete {0} failed; the file is reported as non-existent", f); return true; } else { /* *The delete failed and the file exists. Log a message if that *level is enabled and return false to indicate the failure. */ LOG.log(WARNING, "Error attempting to delete {0}", f); return false; } } /** * Opens a stream to the specified output file, retrying if necessary. * * @param out the output File for which a stream is needed * @return the FileOutputStream * @throws IOException for any errors opening the stream */ public static FileOutputStream openFileOutputStream(File out) throws IOException { FileOutputStreamWork work = new FileOutputStreamWork(out); int retries = doWithRetry(work); if (retries > 0) { LOG.log(DEBUG, "Retried {0} times the output to {1}", retries, out); } if (work.workComplete()) { return work.getStream(); } else { IOException ioe = new IOException(); ioe.initCause(work.getLastError()); throw ioe; } } /** * Return a set of all the files (File objects) under the directory specified, with * relative pathnames filtered with the filename filter (can be null for all files). */ public static Set getAllFilesUnder(File directory, FilenameFilter filenameFilter) throws IOException { if (!directory.exists() || !directory.isDirectory()) { throw new IOException("Problem with: " + directory + ". You must supply a directory that exists"); } return getAllFilesUnder(directory, filenameFilter, true); } public static Set getAllFilesUnder(File directory, FilenameFilter filenameFilter, boolean relativize) throws IOException { Set allFiles = new TreeSet<>(); File relativizingDir = relativize ? directory : null; recursiveGetFilesUnder( relativizingDir, directory, filenameFilter, allFiles, false ); return allFiles; } public static Set getAllFilesAndDirectoriesUnder(File directory) throws IOException { if (!directory.exists() || !directory.isDirectory()) { throw new IOException("Problem with: " + directory + ". You must supply a directory that exists"); } Set allFiles = new TreeSet<>(); recursiveGetFilesUnder(directory, directory, null, allFiles, true); return allFiles; } // relativizingRoot can be null, in which case no relativizing is // performed. private static void recursiveGetFilesUnder(File relativizingRoot, File directory, FilenameFilter filenameFilter, Set set, boolean returnDirectories) { File[] files = listFiles(directory, filenameFilter); for (File file : files) { if (file.isDirectory()) { recursiveGetFilesUnder(relativizingRoot, file, filenameFilter, set, returnDirectories); if (returnDirectories) { if( relativizingRoot != null ) { set.add(relativize(relativizingRoot, file)); } else { set.add(file); } } } else { if( relativizingRoot != null ) { set.add(relativize(relativizingRoot, file)); } else { set.add(file); } } } } /** * Given a directory and a fully-qualified file somewhere * under that directory, return the portion of the child * that is relative to the parent. */ public static File relativize(File parent, File child) { String baseDir = parent.getAbsolutePath(); String baseDirAndChild = child.getAbsolutePath(); String relative = baseDirAndChild.substring(baseDir.length(), baseDirAndChild.length()); // Strip off any extraneous file separator character. if( relative.startsWith(File.separator) ) { relative = relative.substring(1); } return new File(relative); } /** * Executes the supplied work object until the work is done or the max. * retry count is reached. * * @param work the RetriableWork implementation to be run * @return the number of retries performed; 0 indicates the work succeeded without having to retry */ private static int doWithRetry(RetriableWork work) { int retries = 0; /* *Try the work the first time. Ideally this will work. */ work.run(); /* *If the work failed and this is Windows - on which running gc may *unlock the locked file - then begin the retries. */ if (!work.workComplete() && OS.isWindows()) { while (!work.workComplete() && retries++ < FILE_OPERATION_MAX_RETRIES) { try { Thread.sleep(FILE_OPERATION_SLEEP_DELAY_MS); } catch (InterruptedException ex) { } LOG.log(DEBUG, "Performing gc to try to force file closures"); System.gc(); work.run(); } } return retries; } /** * Creates a String listing the absolute paths of files, separated by * the platform's line separator. * * @param files the Collection of File objects to be listed * @return String containing the absolute paths of the files with the line separator between them */ public static String formatFileCollection(Collection files) { StringBuilder sb = new StringBuilder(); String lineSep = System.getProperty("line.separator"); String prefix = ""; for (File f : files) { sb.append(prefix).append(f.getAbsolutePath()); prefix = lineSep; } return sb.toString(); } /////////////////////////////////////////////////////////////////////////// public static File getDirectory(File f) { String filename = f.getAbsolutePath(); return new File((new File(filename)).getParent()); } /////////////////////////////////////////////////////////////////////////// public static File createTempFile(File directory) { File f = null; try { f = File.createTempFile(TMPFILENAME, "jar", directory); } catch (IOException ioe) { LOG.log(Level.ERROR, CULoggerInfo.exceptionIO, ioe); } f.deleteOnExit(); // just in case return f; } /** * Returns an array of abstract pathnames that matches with the given * file extension. If the given abstract pathname does not denote a * directory, then this method returns null. If there is no matching * file under the given directory and its sub directories, * it returns null; * * @param dirName dir name under which search will begin * @param ext file extension to look for * @return an array of abstract pathnames that matches with the extension */ public static File[] listAllFiles(File dirName, String ext) { File[] target = null; List list = searchDir(dirName, ext); if ((list != null) && (list.size() > 0)) { target = new File[list.size()]; target = list.toArray(target); } return target; } /** * Returns a list of abstract pathnames that matches with the given * file extension. If the given abstract pathname does not denote a * directory, then this method returns null. If there is no matching * file under the given directory and its sub directories, it returns * an empty list. * * @param dirName dir name under which search will begin * @param ext file extension to look for * @return a list of abstract pathnames of type java.io.File * that matches with the given extension */ public static List searchDir(File dirName, String ext) { List targetList = null; if (dirName.isDirectory()) { targetList = new ArrayList<>(); File[] list = listFiles(dirName); for (File element : list) { if (element.isDirectory()) { targetList.addAll(searchDir(element, ext)); } else { String name = element.toString(); if (hasExtension(name, ext)) { targetList.add(element); } } } } return targetList; } /** * Copies a file. * * @param from Name of file to copy * @param to Name of new file * @throws IOException if an error while copying the content */ public static void copy(String from, String to) throws IOException { //if(!StringUtils.ok(from) || !StringUtils.ok(to)) if (from == null || to == null) { throw new IllegalArgumentException("null or empty filename argument"); } File fin = new File(from); File fout = new File(to); copy(fin, fout); } /** * Copies a file. * * @param fin File to copy * @param fout New file * @throws IOException if an error while copying the content */ public static void copy(File fin, File fout) throws IOException { if (safeIsDirectory(fin)) { copyTree(fin, fout); return; } if (!fin.exists()) { throw new IllegalArgumentException("File source doesn't exist"); } if(!mkdirsMaybe(fout.getParentFile())) { throw new RuntimeException("Can't create parent dir of output file: " + fout); } copyFile(fin, fout); } /** * Copies the entire tree to a new location. * * @param din File pointing at root of tree to copy * @param dout File pointing at root of new tree * @throws IOException if an error while copying the content */ public static void copyTree(File din, File dout) throws IOException { if (!safeIsDirectory(din)) { throw new IllegalArgumentException("Source isn't a directory"); } if(!mkdirsMaybe(dout)) { throw new IllegalArgumentException("Can't create destination directory"); } FileListerRelative flr = new FileListerRelative(din); String[] files = flr.getFiles(); for (String file : files) { File fin = new File(din, file); File fout = new File(dout, file); copy(fin, fout); } } /** * Returns a String with uniform slashes such that all the * occurances of '\\' are replaced with '/'. * In other words, the returned string will have all forward slashes. * Accepts non-null strings only. * * @param inputStr non null String * @return a String which does not contain `\\` character */ public static String makeForwardSlashes(String inputStr) { if (inputStr == null) { throw new IllegalArgumentException("null String FileUtils.makeForwardSlashes"); } return (inputStr.replace('\\', '/')); } /** * Given a string (typically a path), quote the string such that spaces * are protected from interpretation by a Unix or Windows command shell. * Note that this method does not handle quoting for all styles of special * characters. Just for the basic case of strings with spaces. * * @param s input string * @return a String which is quoted to protect spaces */ public static String quoteString(String s) { if (s == null) { throw new IllegalArgumentException("null string"); } if (!s.contains("\'")) { return("\'" + s + "\'"); } else if(!s.contains("\"")) { return("\"" + s + "\""); } else { // Contains a single quote and a double quote. Use backslash // On Unix. Double quotes on Windows. This method does not claim // to support this case well if at all if (OS.isWindows()) { return("\"" + s + "\""); } else { return(s.replaceAll("\040", "\134 ")); } } } /////////////////////////////////////////////////////////////////////////// public static String getIllegalFilenameCharacters() { return ILLEGAL_FILENAME_STRING; } /////////////////////////////////////////////////////////////////////////// static boolean isValidString(String s) { return ((s != null) && (s.length() != 0)); } /** * This method is used to copy a given file to another file * using the buffer sixe specified * * @param fin the source file * @param fout the destination file */ public static void copyFile(File fin, File fout) throws IOException { InputStream inStream = new BufferedInputStream(new FileInputStream(fin)); FileOutputStream fos = FileUtils.openFileOutputStream(fout); copy(inStream, fos, fin.length()); } public static void copy(InputStream in, FileOutputStream out, long size) throws IOException { try { copyWithoutClose(in, out, size); } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } public static void copyWithoutClose(InputStream in, FileOutputStream out, long size) throws IOException { ReadableByteChannel inChannel = Channels.newChannel(in); FileChannel outChannel = out.getChannel(); outChannel.transferFrom(inChannel, 0, size); } public static void copy(InputStream in, OutputStream os, long size) throws IOException { if (os instanceof FileOutputStream) { copy(in, (FileOutputStream) os, size); } else { ReadableByteChannel inChannel = Channels.newChannel(in); WritableByteChannel outChannel = Channels.newChannel(os); if (size==0) { ByteBuffer byteBuffer = ByteBuffer.allocate(10240); int read; do { read = inChannel.read(byteBuffer); if (read>0) { byteBuffer.limit(byteBuffer.position()); byteBuffer.rewind(); outChannel.write(byteBuffer); byteBuffer.clear(); } } while (read!=-1); } else { ByteBuffer byteBuffer; try{ byteBuffer = ByteBuffer.allocate(Long.valueOf(size).intValue()); }catch(Throwable err){ throw new IOException(messages.get("allocate.more.than.java.heap.space", err)); } inChannel.read(byteBuffer); byteBuffer.rewind(); outChannel.write(byteBuffer); } } } /** *Rename, running gc on Windows if needed to try to force open streams to close. *@param fromFile to be renamed *@param toFile name for the renamed file *@return boolean result of the rename attempt */ public static boolean renameFile(File fromFile, File toFile) { RenameFileWork renameWork = new RenameFileWork(fromFile, toFile); int retries = doWithRetry(renameWork); boolean result = renameWork.workComplete(); if (result) { LOG.log(DEBUG, "Attempt to rename {0} to {1} succeeded after {2} retries", fromFile, toFile, retries); } else { LOG.log(WARNING, "Attempt to rename {0} to {1} failed after {2} retries", fromFile, toFile, retries); } return result; } /** Appends the given line at the end of given text file. If the given * file does not exist, an attempt is made to create it. * Note that this method can handle only text files. * @param fileName name of the text file that needs to be appended to * @param line the line to append to * @throws RuntimeException in case of any error - that makes it callable * from a code not within try-catch. Note that NPE will be thrown if either * argument is null. * Note that this method is not tested with String containing characters * with 2 bytes. */ public static void appendText(String fileName, String line) throws RuntimeException { RandomAccessFile file = null; try { final String MODE = "rw"; file = new RandomAccessFile(fileName, MODE); file.seek(file.getFilePointer() + file.length()); file.writeBytes(line); } catch(Exception e) { throw new RuntimeException("FileUtils.appendText()", e); } finally { try { if (file != null) { file.close(); } } catch(Exception e){} } } public static void appendText(String fileName, StringBuffer buffer) throws IOException, FileNotFoundException { appendText(fileName, buffer.toString()); } /////////////////////////////////////////////////////////////////////////// /** A utility routine to read a text file efficiently and return * the contents as a String. Sometimes while reading log files of spawned * processes this kind of facility is handy. Instead of opening files, coding * FileReaders etc. this method could be employed. It is expected that the * file to be read is small . * @param fileName String representing absolute path of the file * @return String representing the contents of the file, empty String for an empty file * @throws java.io.IOException if there is an i/o error. * @throws java.io.FileNotFoundException if the file could not be found */ public static String readSmallFile(final String fileName) throws IOException, FileNotFoundException { return (readSmallFile(new File(fileName)) ); } public static String readSmallFile(final File file) throws IOException { final BufferedReader bf = new BufferedReader(new FileReader(file)); final StringBuilder sb = new StringBuilder(); //preferred over StringBuffer, no need to synchronize String line = null; try { while ( (line = bf.readLine()) != null ) { sb.append(line); sb.append(System.getProperty("line.separator")); } } finally { try { bf.close(); } catch (Exception e) {} } return ( sb.toString() ); } /** * If the path dir/file does not exist, look for it in the classpath. If found * in classpath, create dir/file. * * @param file - path to look for * @param dir - directory where the path file should exist * @return the File representing dir/file. If that does not exist, return null. * @throws IOException */ public static File getManagedFile(String file, File dir) throws IOException { File f = new File(dir, file); if (f.exists()) { return f; } InputStream is = null, bis = null; OutputStream os = null; try { is = Thread.currentThread().getContextClassLoader().getResourceAsStream(file); if (is == null) { return null; } bis = new BufferedInputStream(is); if(!mkdirsMaybe(f.getParentFile())) { throw new RuntimeException("Can't create parent dir of output file: " + f); } os = new BufferedOutputStream(FileUtils.openFileOutputStream(f)); byte buf[] = new byte[10240]; int len = 0; while ((len =bis.read(buf)) > 0) { os.write(buf, 0, len); } return f; } finally { if (os != null) { try { os.close(); } catch (IOException ex) {} } if (bis != null) { try { bis.close(); } catch (IOException ex) {} } if (is != null) { try { is.close(); } catch (IOException ex) {} } } } /** * Write the String to a file. Then make the file readable and writable. * If the file already exists it will be truncated and the contents replaced * with the String argument. * @param s The String to write to the file * @param f The file to write the String to * @throws IOException if any errors */ public static void writeStringToFile(String s, File f) throws IOException { Writer writer = null; try { writer = new PrintWriter(f); writer.write(s); } finally { if(writer != null) { try { writer.close(); } catch(Exception e) { //ignore } f.setReadable(true); f.setWritable(true); } } } /** * Find files matching the regular expression in the given directory * @param dir the directory to search * @param regexp the regular expression pattern * @return either an array of matching File objects or an empty array. Guaranteed * to never return null */ public static File[] findFilesInDir(File dir, final String regexp) { try { File[] matches = dir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.matches(regexp); } }); if (matches != null) { return matches; } } catch (Exception e) { // fall through } return new File[0]; } /** * Read in the given resourceName as a resource, and convert to a String * * @param resourceName * @return the contents of the resource as a String or null if absent */ public static String resourceToString(String resourceName) { byte[] bytes = resourceToBytes(resourceName); return bytes == null ? null : new String(bytes); } /** * Read in the given resourceName as a resource, and convert to a byte array * * @param resourceName * @return the contents of the resource as a byte array or null if absent */ public static byte[] resourceToBytes(String resourceName) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); InputStream is = cl.getResourceAsStream(resourceName); if (is == null) { return null; } try { is = new BufferedInputStream(is); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int n; while ((n = is.read(buffer)) != -1) { baos.write(buffer, 0, n); } is.close(); return baos.toByteArray(); } catch (Exception e) { try { is.close(); } catch (Exception ex) { // ignore... } return null; } } /** * Represents a unit of work that should be retried, if needed, until it * succeeds or the configured retry limit is reached. *

* The run method required by the Runnable interface is invoked * to perform the work. */ private interface RetriableWork extends Runnable { /** * Returns whether the work to be done by this instance of RetriableWork * has been completed successfully. *

* This method may be invoked multiple times and so should not have * side effects. * * @return whether the work has been successfully completed */ boolean workComplete(); } /** *Retriable work for renaming a file. */ private static class RenameFileWork implements RetriableWork { private final File originalFile; private final File newFile; private boolean renameResult = false; public RenameFileWork(File originalFile, File newFile) { this.originalFile = originalFile; this.newFile = newFile; } @Override public boolean workComplete() { return renameResult; } @Override public void run() { renameResult = originalFile.renameTo(newFile); } } /** * Retriable work for opening a FileOutputStream. */ private static class FileOutputStreamWork implements RetriableWork { private FileOutputStream fos = null; private Throwable lastError = null; private final File out; public FileOutputStreamWork(File out) { this.out = out; } @Override public boolean workComplete() { return fos != null; } @Override public void run() { try { fos = new FileOutputStream(out); lastError = null; } catch (IOException ioe) { lastError = ioe; } } public FileOutputStream getStream() { return fos; } public Throwable getLastError() { return lastError; } } /** * Retriable work for deleting a file */ private static class DeleteFileWork implements RetriableWork { private final File deleteMe; private boolean complete = false; private DeleteFileWork(File deleteMe) { this.deleteMe = deleteMe; } @Override public void run() { if (complete) { return; } if (deleteMe.delete()) { complete = true; } } @Override public boolean workComplete() { return complete; } } /////////////////////////////////////////////////////////////////////////// private final static char[] ILLEGAL_FILENAME_CHARS = {'/', '\\', ':', '*', '?', '"', '<', '>', '|'}; private final static String ILLEGAL_FILENAME_STRING = "\\/:*?\"<>|"; private final static char REPLACEMENT_CHAR = '_'; private final static char BLANK = ' '; private final static char DOT = '.'; private static String TMPFILENAME = "scratch"; /* *The following property names are private, unsupported, and unpublished. */ private static final int FILE_OPERATION_MAX_RETRIES = Integer.getInteger("com.sun.appserv.winFileLockRetryLimit", 5).intValue(); private static final int FILE_OPERATION_SLEEP_DELAY_MS = Integer.getInteger("com.sun.appserv.winFileLockRetryDelay", 1000).intValue(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy