org.openbp.common.io.FileUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openbp-common Show documentation
Show all versions of openbp-common Show documentation
Common base for all OpenBP projects
The newest version!
/*
* 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 org.openbp.common.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import org.openbp.common.string.StringUtil;
import org.openbp.common.string.shellmatcher.ShellMatcher;
/**
* The FileUtil class provides some additional static file management utility methods
* not contained in java.io.File.
* The class contains static method only.
*
* @author Heiko Erhardt
*/
public final class FileUtil
{
/** File type 'any file' (argument for {@link #list}) */
public static final int FILETYPE_ANY = 0;
/** File type 'file' (argument for {@link #list}) */
public static final int FILETYPE_FILE = 1;
/** File type 'directory' (argument for {@link #list}) */
public static final int FILETYPE_DIR = 2;
/**
* Do not instantiate this class!
*/
private FileUtil()
{
}
/**
* Returns an array of strings naming the files and directories in a
* directory, matching the files against an optional pattern and file type.
*
* If this abstract pathname does not denote a directory, then this
* method returns null. Otherwise an array of strings is
* returned, one for each file or directory in the directory. Names
* denoting the directory itself and the directory's parent directory are
* not included in the result. Each string is a file name rather than a
* complete path.
*
* There is no guarantee that the name strings in the resulting array
* will appear in any specific order; they are not, in particular,
* guaranteed to appear in alphabetical order.
*
* @param dirName Name of the directory or null for the current directory
* @param pattern Wildcard pattern (see the {@link ShellMatcher} class)
* The pattern is case-insensitive.
* @param fileType Type of file to be listed ({@link #FILETYPE_ANY}/{@link #FILETYPE_FILE}/{@link #FILETYPE_DIR})
*
* KNOWN BUG: It seems that on Win32 systems, it does always return
* all files and directories matching pattern, regardless of fileType.
*
* @return An array of strings naming the files and directories in the
* directory. The array will be empty if the directory is empty.
* Returns null if the pathname does not denote a directory, or if an
* I/O error occurs.
*
* @throws SecurityException
* If a security manager exists and denies read access to the directory
*/
public static String [] list(String dirName, String pattern, int fileType)
{
PatternFilenameFilter pff = null;
if (pattern != null || fileType != FILETYPE_ANY)
pff = new PatternFilenameFilter(pattern, fileType);
File dir = new File(dirName);
String [] fileNames = dir.list(pff);
return fileNames;
}
/**
* Internal file name filter class for list method.
*/
static class PatternFilenameFilter
implements FilenameFilter
{
/** Shell matcher object for pattern match */
private ShellMatcher sm = null;
/** Type of file to be listed (FILETYPE_ANY/FILETYPE_FILE/FILETYPE_DIR) */
private int fileType;
/**
* Constructor.
*
* @param pattern Wildcard pattern (see the {@link ShellMatcher} class) or null
* The pattern is case-insensitive.
* @param fileType Type of file to be listed (FILETYPE_ANY/FILETYPE_FILE/FILETYPE_DIR)
*/
public PatternFilenameFilter(String pattern, int fileType)
{
if (pattern != null)
{
sm = new ShellMatcher(pattern);
sm.setIgnoreCase(true);
}
this.fileType = fileType;
}
/**
* Tests if a specified file should be included in a file list.
*
* @param dir Directory in which the file was found
* @param name Name of the file
* @return
* true if and only if the name should be included in the file list
* false otherwise
*/
public boolean accept(File dir, String name)
{
if (sm != null)
{
if (!sm.match(name))
return false;
}
if (fileType != FILETYPE_ANY)
{
File f = new File(StringUtil.buildPath(dir.getPath(), name));
if (f.isDirectory())
{
if (fileType == FILETYPE_FILE)
return false;
}
else
{
if (fileType == FILETYPE_DIR)
return false;
}
}
return true;
}
}
/**
* Recursively removes a file or directory.
* If the file is a directory and is not empty,
* its sub directories and files will be deleted also.
*
* @param src File or directory to delete
* @throws IOException If the file could not be deleted
*/
public static void remove(File src)
throws IOException
{
if (src.isFile())
{
if (!src.delete())
throw new IOException("Can't delete file '" + src.getPath() + "'");
}
else
{
String [] files = src.list();
if (files == null)
return;
for (int i = 0; i < files.length; i++)
{
// remove sub-directories recursive
remove(new File(src, files [i]));
}
// remove empty directory
if (!src.delete())
throw new IOException("Can't delete directory '" + src.getPath() + "'");
}
}
/**
* Copy a file or directory.
* Can be used for copying files and/or directories.
* For some reason, there is no java.io.File.copy() method, hence this method.
* It can be used to copy file2file, file2directory, or
* directory2directory (recursively).
*
* @param src Source file or directory
* @param dest Destination file or directory
* @exception IOException If the operation fails
*/
public static void copy(File src, File dest)
throws IOException
{
copy(src, dest, null);
}
/**
* Copy a file or directory using a file name filter.
* Can be used for copying files and/or directories.
* For some reason, there is no java.io.File.copy() method, hence this method.
* It can be used to copy file2file, file2directory, or
* directory2directory (recursively).
*
* @param src Source file or directory
* @param dest Destination file or directory
* @param filter File name filter that determines which files of a directory will be copied
* @exception IOException If the operation fails
*/
public static void copy(File src, File dest, FilenameFilter filter)
throws IOException
{
// Make sure the specified source exists and is readable.
if (!src.exists())
throw new IOException("Source file not found: " + src);
if (!src.canRead())
throw new IOException("Source file is unreadable: " + src);
if (src.isFile())
{
if (!dest.exists())
{
File parentdir = getParent(dest, false);
if (parentdir != null && !parentdir.exists())
parentdir.mkdirs();
}
else if (dest.isDirectory())
{
// Search for the last '/' before the pattern and get the directory
String srcStr = src.toString();
int iSep = srcStr.lastIndexOf(StringUtil.FOLDER_SEP_CHAR);
String baseName = iSep >= 0 ? srcStr.substring(iSep + 1) : srcStr;
dest = new File(dest + StringUtil.FOLDER_SEP + baseName);
}
}
else if (src.isDirectory())
{
if (dest.isFile())
throw new IOException("Cannot copy directory " + src + " to file " + dest);
if (!dest.exists())
dest.mkdirs();
}
// If we've gotten this far everything is OK and we can copy.
if (src.isFile())
{
FileInputStream source = null;
FileOutputStream destination = null;
try
{
source = new FileInputStream(src);
destination = new FileOutputStream(dest);
byte [] buffer = new byte [1024];
while (true)
{
int bytesRead = source.read(buffer);
if (bytesRead == -1)
break;
destination.write(buffer, 0, bytesRead);
}
}
finally
{
if (source != null)
{
try
{
source.close();
}
catch (IOException e)
{
}
}
if (destination != null)
{
try
{
destination.close();
}
catch (IOException e)
{
}
}
}
}
else if (src.isDirectory())
{
String [] files = src.list(filter);
for (int i = 0; i < files.length; i++)
{
String member = files [i];
String srcMember = StringUtil.buildPath(src.getPath(), member);
String destMember = StringUtil.buildPath(dest.getPath(), member);
if ((new File(srcMember)).isDirectory())
{
copy(new File(srcMember), new File(destMember), filter);
}
else
{
FileInputStream source = null;
FileOutputStream destination = null;
try
{
source = new FileInputStream(srcMember);
destination = new FileOutputStream(destMember);
byte [] buffer = new byte [1024];
for (;;)
{
int bytesRead = source.read(buffer);
if (bytesRead == -1)
break;
destination.write(buffer, 0, bytesRead);
}
}
finally
{
if (source != null)
{
try
{
source.close();
}
catch (IOException e)
{
}
}
if (destination != null)
{
try
{
destination.close();
}
catch (IOException e)
{
}
}
}
}
}
}
}
/**
* File.getParent() can return null when the file is specified without
* a directory or is in the root directory. This method handles those cases.
*
* @param f The target File to analyze
* @param returnCurrent
* true Returns a file object (the current directory) also if the file does not
* contain a path specification.
* false Returns null if the file does not contain a path specification.
* @return The parent directory as a File
*/
public static File getParent(File f, boolean returnCurrent)
{
// try/catch due to a bug causing f.getParent to throw an exception if the
// file does not contain a path specification
try
{
String dirname = f.getParent();
if (dirname != null)
{
// Regular directory
return new File(dirname);
}
if (f.isAbsolute())
{
// Root directory
return new File(StringUtil.FOLDER_SEP);
}
// Current directory
}
catch (Exception ex)
{
// Current directory
}
return returnCurrent ? new File(System.getProperty("user.dir")) : null;
}
}