
dorkbox.util.FileUtil Maven / Gradle / Ivy
/*
* Copyright 2010 dorkbox, llc
*
* 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 dorkbox.util;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* File related utilities.
*
*
* Contains code from FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
@SuppressWarnings({"WeakerAccess", "Duplicates", "unused"})
public
class FileUtil {
private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);
/**
* The Unix separator character.
*/
private static final char UNIX_SEPARATOR = '/';
/**
* The Windows separator character.
*/
private static final char WINDOWS_SEPARATOR = '\\';
/**
* The system separator character.
*/
private static final char SYSTEM_SEPARATOR = File.separatorChar;
/**
* The separator character that is the opposite of the system separator.
*/
private static final char OTHER_SEPARATOR;
static {
if (OS.isWindows()) {
OTHER_SEPARATOR = UNIX_SEPARATOR;
}
else {
OTHER_SEPARATOR = WINDOWS_SEPARATOR;
}
}
public static byte[] ZIP_HEADER = {'P', 'K', (byte) 0x3, (byte) 0x4};
/**
* Converts the content of a file into a list of strings. Lines are trimmed.
*
* @param file the input file to read. Throws an error if this file cannot be read.
* @param includeEmptyLines true if you want the resulting list of String to include blank/empty lines from the file
*
* @return A list of strings, one line per string, of the content
*/
public static
List read(final File file, final boolean includeEmptyLines) throws IOException {
List lines = new ArrayList();
FileReader fileReader = new FileReader(file);
try {
BufferedReader bin = new BufferedReader(fileReader);
String line;
if (includeEmptyLines) {
while (( line = bin.readLine()) != null) {
lines.add(line);
}
} else {
while ((line = bin.readLine()) != null) {
if (!line.isEmpty()) {
lines.add(line);
}
}
}
} finally {
IO.closeQuietly(fileReader);
}
return lines;
}
/**
* Convenience method that converts the content of a file into a giant string.
*
* @param file the input file to read. Throws an error if this file cannot be read.
*
* @return A string, matching the contents of the file
*/
public static
String readAsString(final File file) throws IOException {
StringBuilder stringBuilder = new StringBuilder((int) (file.length()));
read(file, stringBuilder);
return stringBuilder.toString();
}
/**
* Writes the content of a file to the passed in StringBuilder.
*
* @param file the input file to read. Throws an error if this file cannot be read.
* @param stringBuilder the stringBuilder this file will be written to
*/
public static
void read(final File file, final StringBuilder stringBuilder) throws IOException {
FileReader fileReader = new FileReader(file);
try {
BufferedReader bin = new BufferedReader(fileReader);
String line;
while (( line = bin.readLine()) != null) {
stringBuilder.append(line).append(OS.LINE_SEPARATOR);
}
} finally {
IO.closeQuietly(fileReader);
}
}
/**
* Reads the contents of the supplied input stream into a list of lines.
*
* @return Always returns a list, even if the file does not exist, or there are errors reading it.
*/
public static
List readLines(final File file) {
FileReader fileReader = null;
try {
fileReader = new FileReader(file);
} catch (FileNotFoundException ignored) {
return new ArrayList();
}
return readLines(fileReader);
}
/**
* Reads the contents of the supplied input stream into a list of lines.
*
* Closes the reader on successful or failed completion.
*
* @return Always returns a list, even if the file does not exist, or there are errors reading it.
*/
public static
List readLines(Reader in) {
List lines = new ArrayList();
try {
BufferedReader bin = new BufferedReader(in);
String line;
try {
while ((line = bin.readLine()) != null) {
lines.add(line);
}
} catch (IOException ignored) {
}
} finally {
IO.closeQuietly(in);
}
return lines;
}
/**
* Renames a file. Windows has all sorts of problems which are worked around.
*
* @return true if successful, false otherwise
*/
public static
boolean renameTo(File source, File dest) {
// if we're on a civilized operating system we may be able to simple
// rename it
if (source.renameTo(dest)) {
return true;
}
// fall back to trying to rename the old file out of the way, rename the
// new file into
// place and then delete the old file
if (dest.exists()) {
File temp = new File(dest.getPath() + "_old");
if (temp.exists()) {
if (!temp.delete()) {
logger.warn("Failed to delete old intermediate file {}.", temp);
// the subsequent code will probably fail
}
}
if (dest.renameTo(temp)) {
if (source.renameTo(dest)) {
if (temp.delete()) {
logger.warn("Failed to delete intermediate file {}.", temp);
}
return true;
}
}
}
// as a last resort, try copying the old data over the new
FileInputStream fin = null;
FileOutputStream fout = null;
try {
fin = new FileInputStream(source);
fout = new FileOutputStream(dest);
IO.copyStream(fin, fout);
IO.close(fin);
if (!source.delete()) {
logger.warn("Failed to delete {} after brute force copy to {}.", source, dest);
}
return true;
} catch (IOException ioe) {
logger.warn("Failed to copy {} to {}.", source, dest, ioe);
return false;
} finally {
IO.close(fin);
IO.close(fout);
}
}
/**
* Copies a files from one location to another. Overwriting any existing file at the destination.
*/
public static
File copyFile(String in, File out) throws IOException {
return copyFile(new File(in), out);
}
/**
* Copies a files from one location to another. Overwriting any existing file at the destination.
*/
public static
File copyFile(File in, String out) throws IOException {
return copyFile(in, new File(out));
}
/**
* Copies a files from one location to another. Overwriting any existing file at the destination.
*/
public static
File copyFile(String in, String out) throws IOException {
return copyFile(new File(in), new File(out));
}
/**
* Copies a files from one location to another. Overwriting any existing file at the destination.
*/
public static
File copyFileToDir(String in, String out) throws IOException {
return copyFileToDir(new File(in), new File(out));
}
/**
* Copies a files from one location to another. Overwriting any existing file at the destination.
* If the out file is a directory, then the in file will be copied to the directory
*/
public static
File copyFileToDir(File in, File out) throws IOException {
if (in == null) {
throw new IllegalArgumentException("in cannot be null.");
}
if (out == null) {
throw new IllegalArgumentException("out cannot be null.");
}
// copy the file to the directory instead
if (!out.isDirectory()) {
throw new IOException("Out file is not a directory! '" + out.getAbsolutePath() + "'");
}
return copyFile(in, new File(out, in.getName()));
}
/**
* Copies a files from one location to another. Overwriting any existing file at the destination.
*/
public static
File copyFile(File in, File out) throws IOException {
if (in == null) {
throw new IllegalArgumentException("in cannot be null.");
}
if (out == null) {
throw new IllegalArgumentException("out cannot be null.");
}
String normalizedIn = normalize(in).getAbsolutePath();
String normalizedout = normalize(out).getAbsolutePath();
if (normalizedIn.equalsIgnoreCase(normalizedout)) {
logger.warn("Source equals destination! " + normalizedIn);
return out;
}
// if out doesn't exist, then create it.
File parentOut = out.getParentFile();
if (!parentOut.canWrite()) {
//noinspection ResultOfMethodCallIgnored
parentOut.mkdirs();
}
Logger logger2 = logger;
if (logger2.isTraceEnabled()) {
logger2.trace("Copying file: {} --> {}", in, out);
}
FileChannel sourceChannel = null;
FileChannel destinationChannel = null;
try {
sourceChannel = new FileInputStream(normalizedIn).getChannel();
destinationChannel = new FileOutputStream(normalizedout).getChannel();
if (sourceChannel.size() == 0) {
logger2.warn("Source size is ZERO: " + normalizedIn);
}
sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
} finally {
try {
if (sourceChannel != null) {
sourceChannel.close();
}
} catch (Exception ignored) {
}
try {
if (destinationChannel != null) {
destinationChannel.close();
}
} catch (Exception ignored) {
}
}
//noinspection ResultOfMethodCallIgnored
out.setLastModified(in.lastModified());
return out;
}
/**
* Copies the contents of file two onto the END of file one.
*/
public static
File concatFiles(File one, File two) {
if (one == null) {
throw new IllegalArgumentException("one cannot be null.");
}
if (two == null) {
throw new IllegalArgumentException("two cannot be null.");
}
String normalizedOne = normalize(one).getAbsolutePath();
String normalizedTwo = normalize(two).getAbsolutePath();
Logger logger2 = logger;
if (logger2.isTraceEnabled()) {
logger2.trace("Cocating file: {} --> {}", one, two);
}
FileChannel channelOne = null;
FileChannel channelTwo = null;
try {
// open it in append mode
channelOne = new FileOutputStream(normalizedOne, true).getChannel();
channelTwo = new FileInputStream(normalizedTwo).getChannel();
long size = two.length();
while (size > 0) {
size -= channelOne.transferFrom(channelTwo, 0, size);
}
} catch (Exception ignored) {
ignored.printStackTrace();
} finally {
try {
if (channelOne != null) {
channelOne.close();
}
} catch (Exception ignored) {
}
try {
if (channelTwo != null) {
channelTwo.close();
}
} catch (Exception ignored) {
}
}
//noinspection ResultOfMethodCallIgnored
one.setLastModified(System.currentTimeMillis());
return one;
}
/**
* Moves a file, overwriting any existing file at the destination.
*/
public static
File moveFile(String in, File out) throws IOException {
return moveFile(new File(in), out);
}
/**
* Moves a file, overwriting any existing file at the destination.
*/
public static
File moveFile(File in, String out) throws IOException {
return moveFile(in, new File(out));
}
/**
* Moves a file, overwriting any existing file at the destination.
*/
public static
File moveFile(String in, String out) throws IOException {
return moveFile(new File(in), new File(out));
}
/**
* Moves a file, overwriting any existing file at the destination.
*/
public static
File moveFile(File in, File out) throws IOException {
if (in == null) {
throw new IllegalArgumentException("in cannot be null.");
}
if (out == null) {
throw new IllegalArgumentException("out cannot be null.");
}
if (out.canRead()) {
//noinspection ResultOfMethodCallIgnored
out.delete();
}
boolean renameSuccess = renameTo(in, out);
if (!renameSuccess) {
throw new IOException("Unable to move file: '" + in.getAbsolutePath() + "' -> '" + out.getAbsolutePath() + "'");
}
return out;
}
/**
* Copies a directory from one location to another
*/
public static
void copyDirectory(String src, String dest, String... namesToIgnore) throws IOException {
copyDirectory(new File(src), new File(dest), namesToIgnore);
}
/**
* Copies a directory from one location to another
*/
public static
void copyDirectory(File src_, File dest_, String... namesToIgnore) throws IOException {
File src = FileUtil.normalize(src_);
File dest = FileUtil.normalize(dest_);
if (namesToIgnore.length > 0) {
String name = src.getName();
for (String ignore : namesToIgnore) {
if (name.equals(ignore)) {
return;
}
}
}
if (src.isDirectory()) {
// if directory not exists, create it
if (!dest.exists()) {
//noinspection ResultOfMethodCallIgnored
dest.mkdir();
Logger logger2 = logger;
if (logger2.isTraceEnabled()) {
logger2.trace("Directory copied from {} --> {}", src, dest);
}
}
// list all the directory contents
String files[] = src.list();
if (files != null) {
for (String file : files) {
// construct the src and dest file structure
File srcFile = new File(src, file);
File destFile = new File(dest, file);
// recursive copy
copyDirectory(srcFile, destFile, namesToIgnore);
}
}
}
else {
// if file, then copy it
copyFile(src, dest);
}
}
/**
* Safely moves a directory from one location to another (by copying it first, then deleting the original).
*/
public static
void moveDirectory(String src, String dest, String... fileNamesToIgnore) throws IOException {
moveDirectory(new File(src), new File(dest), fileNamesToIgnore);
}
/**
* Safely moves a directory from one location to another (by copying it first, then deleting the original).
*/
public static
void moveDirectory(File src, File dest, String... fileNamesToIgnore) throws IOException {
if (fileNamesToIgnore.length > 0) {
String name = src.getName();
for (String ignore : fileNamesToIgnore) {
if (name.equals(ignore)) {
return;
}
}
}
if (src.isDirectory()) {
// if directory not exists, create it
if (!dest.exists()) {
//noinspection ResultOfMethodCallIgnored
dest.mkdir();
Logger logger2 = logger;
if (logger2.isTraceEnabled()) {
logger2.trace("Directory copied from {} --> {}", src, dest);
}
}
// list all the directory contents
String files[] = src.list();
if (files != null) {
for (String file : files) {
// construct the src and dest file structure
File srcFile = new File(src, file);
File destFile = new File(dest, file);
// recursive copy
moveDirectory(srcFile, destFile, fileNamesToIgnore);
}
}
}
else {
// if file, then copy it
moveFile(src, dest);
}
}
/**
* Deletes a file or directory and all files and sub-directories under it.
*
* @param fileNamesToIgnore if prefaced with a '/', it will ignore as a directory instead of file
* @return true iff the file/dir was deleted
*/
public static
boolean delete(String fileName, String... fileNamesToIgnore) {
if (fileName == null) {
throw new IllegalArgumentException("fileName cannot be null.");
}
return delete(new File(fileName), fileNamesToIgnore);
}
/**
* Deletes a file, directory + all files and sub-directories under it. The directory is ALSO deleted if it because empty as a result
* of this operation
*
* @param namesToIgnore if prefaced with a '/', it will treat the name to ignore as a directory instead of file
*
* @return true IFF the file/dir was deleted or didn't exist at first
*/
public static
boolean delete(File file, String... namesToIgnore) {
if (!file.exists()) {
return true;
}
boolean thingsDeleted = false;
boolean ignored = false;
Logger logger2 = logger;
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (int i = 0, n = files.length; i < n; i++) {
boolean delete = true;
final File file2 = files[i];
String name2 = file2.getName();
String name2Full = normalize(file2).getAbsolutePath();
if (file2.isDirectory()) {
for (String name : namesToIgnore) {
if (name.charAt(0) == UNIX_SEPARATOR && name.equals(name2)) {
// only name match if our name To Ignore starts with a / or \
if (logger2.isTraceEnabled()) {
logger2.trace("Skipping delete dir: {}", file2);
}
ignored = true;
delete = false;
break;
}
else if (name.equals(name2Full)) {
// full path match
if (logger2.isTraceEnabled()) {
logger2.trace("Skipping delete dir: {}", file2);
}
ignored = true;
delete = false;
break;
}
}
if (delete) {
if (logger2.isTraceEnabled()) {
logger2.trace("Deleting dir: {}", file2);
}
delete(file2, namesToIgnore);
}
}
else {
for (String name : namesToIgnore) {
if (name.charAt(0) != UNIX_SEPARATOR && name.equals(name2)) {
// only name match
if (logger2.isTraceEnabled()) {
logger2.trace("Skipping delete file: {}", file2);
}
ignored = true;
delete = false;
break;
}
else if (name.equals(name2Full)) {
// full path match
if (logger2.isTraceEnabled()) {
logger2.trace("Skipping delete file: {}", file2);
}
ignored = true;
delete = false;
break;
}
}
if (delete) {
if (logger2.isTraceEnabled()) {
logger2.trace("Deleting file: {}", file2);
}
thingsDeleted |= file2.delete();
}
}
}
}
}
// don't try to delete the dir if there was an ignored file in it
if (ignored) {
if (logger2.isTraceEnabled()) {
logger2.trace("Skipping deleting file: {}", file);
}
return false;
}
if (logger2.isTraceEnabled()) {
logger2.trace("Deleting file: {}", file);
}
thingsDeleted |= file.delete();
return thingsDeleted;
}
/**
* Creates the directories in the specified location.
*/
public static
String mkdir(File location) {
if (location == null) {
throw new IllegalArgumentException("fileDir cannot be null.");
}
String path = normalize(location).getAbsolutePath();
if (location.mkdirs()) {
Logger logger2 = logger;
if (logger2.isTraceEnabled()) {
logger2.trace("Created directory: {}", path);
}
}
return path;
}
/**
* Creates the directories in the specified location.
*/
public static
String mkdir(String location) {
if (location == null) {
throw new IllegalArgumentException("path cannot be null.");
}
return mkdir(new File(location));
}
/**
* Creates a temp file
*/
public static
File tempFile(String fileName) throws IOException {
if (fileName == null) {
throw new IllegalArgumentException("fileName cannot be null");
}
return normalize(File.createTempFile(fileName, null)).getAbsoluteFile();
}
/**
* Creates a temp directory
*/
public static
String tempDirectory(String directoryName) throws IOException {
if (directoryName == null) {
throw new IllegalArgumentException("directoryName cannot be null");
}
File file = File.createTempFile(directoryName, null);
if (!file.delete()) {
throw new IOException("Unable to delete temp file: " + file);
}
if (!file.mkdir()) {
throw new IOException("Unable to create temp directory: " + file);
}
return normalize(file).getAbsolutePath();
}
/**
* @return true if the inputStream is a zip/jar stream. DOES NOT CLOSE THE STREAM
*/
public static
boolean isZipStream(InputStream in) {
if (!in.markSupported()) {
in = new BufferedInputStream(in);
}
boolean isZip = true;
try {
in.mark(ZIP_HEADER.length);
for (int i = 0; i < ZIP_HEADER.length; i++) {
//noinspection NumericCastThatLosesPrecision
if (ZIP_HEADER[i] != (byte) in.read()) {
isZip = false;
break;
}
}
in.reset();
} catch (Exception e) {
isZip = false;
}
return isZip;
}
/**
* @return true if the named file is a zip/jar file
*/
public static
boolean isZipFile(String fileName) {
if (fileName == null) {
throw new IllegalArgumentException("fileName cannot be null");
}
return isZipFile(new File(fileName));
}
/**
* @return true if the file is a zip/jar file
*/
public static
boolean isZipFile(File file) {
boolean isZip = true;
byte[] buffer = new byte[ZIP_HEADER.length];
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(file, "r");
raf.readFully(buffer);
for (int i = 0; i < ZIP_HEADER.length; i++) {
if (buffer[i] != ZIP_HEADER[i]) {
isZip = false;
break;
}
}
} catch (Exception e) {
isZip = false;
if (e instanceof FileNotFoundException) {
e.printStackTrace();
}
} finally {
if (raf != null) {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return isZip;
}
/**
* Unzips a ZIP file
*/
public static
void unzip(String zipFile, String outputDir) throws IOException {
unzipJar(zipFile, outputDir, true);
}
/**
* Unzips a ZIP file
*/
public static
void unzip(File zipFile, File outputDir) throws IOException {
unzipJar(zipFile, outputDir, true);
}
/**
* Unzips a ZIP file. Will close the input stream.
*/
public static
void unzip(ZipInputStream inputStream, String outputDir) throws IOException {
if (outputDir == null) {
throw new IllegalArgumentException("outputDir cannot be null.");
}
unzip(inputStream, new File(outputDir));
}
/**
* Unzips a ZIP file. Will close the input stream.
*/
public static
void unzip(ZipInputStream inputStream, File outputDir) throws IOException {
unzipJar(inputStream, outputDir, true);
}
/**
* Unzips a ZIP file
*/
public static
void unzipJar(String zipFile, String outputDir, boolean extractManifest) throws IOException {
if (zipFile == null) {
throw new IllegalArgumentException("zipFile cannot be null.");
}
if (outputDir == null) {
throw new IllegalArgumentException("outputDir cannot be null.");
}
unjarzip0(new File(zipFile), new File(outputDir), extractManifest);
}
/**
* Unzips a ZIP file
*/
public static
void unzipJar(File zipFile, File outputDir, boolean extractManifest) throws IOException {
if (zipFile == null) {
throw new IllegalArgumentException("zipFile cannot be null.");
}
if (outputDir == null) {
throw new IllegalArgumentException("outputDir cannot be null.");
}
unjarzip0(zipFile, outputDir, extractManifest);
}
/**
* Unzips a ZIP file. Will close the input stream.
*/
public static
void unzipJar(ZipInputStream inputStream, File outputDir, boolean extractManifest) throws IOException {
if (inputStream == null) {
throw new IllegalArgumentException("inputStream cannot be null.");
}
if (outputDir == null) {
throw new IllegalArgumentException("outputDir cannot be null.");
}
unjarzip1(inputStream, outputDir, extractManifest);
}
/**
* Unzips a ZIP or JAR file (and handles the manifest if requested)
*/
private static
void unjarzip0(File zipFile, File outputDir, boolean extractManifest) throws IOException {
if (zipFile == null) {
throw new IllegalArgumentException("zipFile cannot be null.");
}
if (outputDir == null) {
throw new IllegalArgumentException("outputDir cannot be null.");
}
long fileLength = zipFile.length();
if (fileLength > Integer.MAX_VALUE - 1) {
throw new RuntimeException("Source filesize is too large!");
}
ZipInputStream inputStream = new ZipInputStream(new FileInputStream(zipFile));
unjarzip1(inputStream, outputDir, extractManifest);
}
/**
* Unzips a ZIP file
*/
private static
void unjarzip1(ZipInputStream inputStream, File outputDir, boolean extractManifest) throws IOException {
try {
ZipEntry entry;
while ((entry = inputStream.getNextEntry()) != null) {
String name = entry.getName();
if (!extractManifest && name.startsWith("META-INF/")) {
continue;
}
File file = new File(outputDir, name);
if (entry.isDirectory()) {
mkdir(file.getPath());
continue;
}
mkdir(file.getParent());
FileOutputStream output = new FileOutputStream(file);
try {
IO.copyStream(inputStream, output);
} finally {
IO.close(output);
}
}
} finally {
IO.close(inputStream);
}
}
/**
* Parses the specified root directory for ALL files that are in it. All of the sub-directories are searched as well.
*
* This is different, in that it returns ALL FILES, instead of ones that just match a specific extension.
*
* @return the list of all files in the root+sub-dirs.
*/
public static
List parseDir(String rootDirectory) throws IOException {
if (rootDirectory == null) {
throw new IllegalArgumentException("rootDirectory cannot be null");
}
return parseDir(new File(rootDirectory), (String) null);
}
/**
* Parses the specified root directory for ALL files that are in it. All of the sub-directories are searched as well.
*
* This is different, in that it returns ALL FILES, instead of ones that just match a specific extension.
*
* @return the list of all files in the root+sub-dirs.
*/
public static
List parseDir(File rootDirectory) throws IOException {
return parseDir(rootDirectory, (String) null);
}
/**
* Parses the specified root directory for files that end in the extension to match. All of the sub-directories are searched as well.
*
* @return the list of all files in the root+sub-dirs that match the given extension.
*/
public static
List parseDir(File rootDirectory, String... extensionsToMatch) throws IOException {
List jarList = new LinkedList();
LinkedList directories = new LinkedList();
rootDirectory = FileUtil.normalize(rootDirectory);
if (!rootDirectory.exists()) {
throw new IOException("Location does not exist: " + rootDirectory.getAbsolutePath());
}
if (rootDirectory.isDirectory()) {
directories.add(rootDirectory);
while (directories.peek() != null) {
File dir = directories.poll();
File[] listFiles = dir.listFiles();
if (listFiles != null) {
for (File file : listFiles) {
if (file.isDirectory()) {
directories.add(file);
}
else {
if (extensionsToMatch == null || extensionsToMatch.length == 0 || extensionsToMatch[0] == null) {
jarList.add(file);
}
else {
for (String e : extensionsToMatch) {
if (file.getAbsolutePath().endsWith(e)) {
jarList.add(file);
}
}
}
}
}
}
}
}
else {
throw new IOException("Cannot search directory children if the dir is a file name: " + rootDirectory.getAbsolutePath());
}
return jarList;
}
/**
* Gets the relative path of a file to a specific directory in it's hierarchy.
*
* For example: getChildRelativeToDir("/a/b/c/d/e.bah", "c") -> "d/e.bah"
*
* @return null if there is no child
*/
public static
String getChildRelativeToDir(String fileName, String dirInHeirarchy) {
if (fileName == null || fileName.isEmpty()) {
throw new IllegalArgumentException("fileName cannot be null.");
}
return getChildRelativeToDir(new File(fileName), dirInHeirarchy);
}
/**
* Gets the relative path of a file to a specific directory in it's hierarchy.
*
* For example: getChildRelativeToDir("/a/b/c/d/e.bah", "c") -> "d/e.bah"
*
* @return null if there is no child
*/
public static
String getChildRelativeToDir(File file, String dirInHeirarchy) {
if (file == null) {
throw new IllegalArgumentException("file cannot be null.");
}
if (dirInHeirarchy == null || dirInHeirarchy.isEmpty()) {
throw new IllegalArgumentException("dirInHeirarchy cannot be null.");
}
String[] split = dirInHeirarchy.split(File.separator);
int splitIndex = split.length - 1;
String absolutePath = file.getAbsolutePath();
File parent = file;
String parentName;
if (splitIndex == 0) {
// match on ONE dir
while (parent != null) {
parentName = parent.getName();
if (parentName.equals(dirInHeirarchy)) {
parentName = parent.getAbsolutePath();
return absolutePath.substring(parentName.length() + 1);
}
parent = parent.getParentFile();
}
}
else {
// match on MANY dir. They must be "in-order"
boolean matched = false;
while (parent != null) {
parentName = parent.getName();
if (matched) {
if (parentName.equals(split[splitIndex])) {
splitIndex--;
if (splitIndex < 0) {
// this means the ENTIRE path matched
if (absolutePath.length() == dirInHeirarchy.length()) {
return null;
}
// +1 to account for the separator char
return absolutePath.substring(dirInHeirarchy.length() + 1, absolutePath.length());
}
}
else {
// because it has to be "in-order", if it doesn't match, we immediately abort
return null;
}
}
else {
if (parentName.equals(split[splitIndex])) {
matched = true;
splitIndex--;
}
}
parent = parent.getParentFile();
}
}
return null;
}
/**
* Gets the PARENT relative path of a file to a specific directory in it's hierarchy.
*
* For example: getParentRelativeToDir("/a/b/c/d/e.bah", "c") -> "/a/b"
*/
public static
String getParentRelativeToDir(String fileName, String dirInHeirarchy) {
if (fileName == null || fileName.isEmpty()) {
throw new IllegalArgumentException("fileName cannot be null.");
}
return getParentRelativeToDir(new File(fileName), dirInHeirarchy);
}
/**
* Gets the relative path of a file to a specific directory in it's hierarchy.
*
* For example: getParentRelativeToDir("/a/b/c/d/e.bah", "c") -> "/a/b"
*
* @return null if it cannot be found
*/
public static
String getParentRelativeToDir(File file, String dirInHeirarchy) {
if (file == null) {
throw new IllegalArgumentException("file cannot be null.");
}
if (dirInHeirarchy == null || dirInHeirarchy.isEmpty()) {
throw new IllegalArgumentException("dirInHeirarchy cannot be null.");
}
String[] split = dirInHeirarchy.split(File.separator);
int splitIndex = split.length - 1;
File parent = file;
String parentName;
if (splitIndex == 0) {
// match on ONE dir
while (parent != null) {
parentName = parent.getName();
if (parentName.equals(dirInHeirarchy)) {
parent = parent.getParentFile();
parentName = parent.getAbsolutePath();
return parentName;
}
parent = parent.getParentFile();
}
}
else {
// match on MANY dir. They must be "in-order"
boolean matched = false;
while (parent != null) {
parentName = parent.getName();
if (matched) {
if (parentName.equals(split[splitIndex])) {
splitIndex--;
if (splitIndex < 0) {
parent = parent.getParentFile();
parentName = parent.getAbsolutePath();
return parentName;
}
}
else {
// because it has to be "in-order", if it doesn't match, we immediately abort
return null;
}
}
else {
if (parentName.equals(split[splitIndex])) {
matched = true;
splitIndex--;
}
}
parent = parent.getParentFile();
}
}
return null;
}
/**
* Extracts a file from a zip into a TEMP file, if possible. The TEMP file is deleted upon JVM exit.
*
* @return the location of the extracted file, or NULL if the file cannot be extracted or doesn't exist.
*/
public static
String extractFromZip(String zipFile, String fileToExtract) throws IOException {
if (zipFile == null) {
throw new IllegalArgumentException("file cannot be null.");
}
if (fileToExtract == null) {
throw new IllegalArgumentException("fileToExtract cannot be null.");
}
ZipInputStream inputStrem = new ZipInputStream(new FileInputStream(zipFile));
try {
while (true) {
ZipEntry entry = inputStrem.getNextEntry();
if (entry == null) {
break;
}
String name = entry.getName();
if (entry.isDirectory()) {
continue;
}
if (name.equals(fileToExtract)) {
File tempFile = FileUtil.tempFile(name);
tempFile.deleteOnExit();
FileOutputStream output = new FileOutputStream(tempFile);
try {
IO.copyStream(inputStrem, output);
} finally {
output.close();
}
return tempFile.getAbsolutePath();
}
}
} finally {
inputStrem.close();
}
return null;
}
/**
* Touches a file, so that it's timestamp is right now. If the file is not created, it will be created automatically.
*
* @return true if the touch succeeded, false otherwise
*/
public static
boolean touch(String file) {
long timestamp = System.currentTimeMillis();
return touch(new File(file).getAbsoluteFile(), timestamp);
}
/**
* Touches a file, so that it's timestamp is right now. If the file is not created, it will be created automatically.
*
* @return true if the touch succeeded, false otherwise
*/
public static
boolean touch(File file) {
long timestamp = System.currentTimeMillis();
return touch(file, timestamp);
}
/**
* Touches a file, so that it's timestamp is right now. If the file is not created, it will be created automatically.
*
* @return true if the touch succeeded, false otherwise
*/
public static
boolean touch(File file, long timestamp) {
if (!file.exists()) {
boolean mkdirs = file.getParentFile()
.mkdirs();
if (!mkdirs) {
// error creating the parent directories.
return false;
}
try {
new FileOutputStream(file).close();
} catch (IOException ignored) {
return false;
}
}
return file.setLastModified(timestamp);
}
//-----------------------------------------------------------------------
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Normalizes a path, removing double and single dot path steps.
*
* THIS IS DIFFERENT in that it might not be a path that resolves to anything
*
* This method normalizes a path to a standard format.
* The input may contain separators in either Unix or Windows format.
* The output will contain separators in the format of the system.
*
* A trailing slash will be retained.
* A double slash will be merged to a single slash (but UNC names are handled).
* A single dot path segment will be removed.
* A double dot will cause that path segment and the one before to be removed.
* If the double dot has no parent path segment to work with, {@code null}
* is returned.
*
* The output will be the same on both Unix and Windows except
* for the separator character.
*
* /foo// --> /foo/
* /foo/./ --> /foo/
* /foo/../bar --> /bar
* /foo/../bar/ --> /bar/
* /foo/../bar/../baz --> /baz
* //foo//./bar --> /foo/bar
* /../ --> null
* ../foo --> null
* foo/bar/.. --> foo/
* foo/../../bar --> null
* foo/../bar --> bar
* //server/foo/../bar --> //server/bar
* //server/../bar --> null
* C:\foo\..\bar --> C:\bar
* C:\..\bar --> null
* ~/foo/../bar/ --> ~/bar/
* ~/../bar --> null
*
* (Note the file separator returned will be correct for Windows/Unix)
*
* @param filename the filename to normalize, null returns null
*
* @return the normalized filename, or null if invalid
*/
public static
String normalizeRaw(String filename) {
return doNormalize(filename, SYSTEM_SEPARATOR, true);
}
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Normalizes a path, removing double and single dot path steps.
*
* This method normalizes a path to a standard format.
* The input may contain separators in either Unix or Windows format.
* The output will contain separators in the format of the system.
*
* A trailing slash will be retained.
* A double slash will be merged to a single slash (but UNC names are handled).
* A single dot path segment will be removed.
* A double dot will cause that path segment and the one before to be removed.
* If the double dot has no parent path segment to work with, {@code null}
* is returned.
*
* The output will be the same on both Unix and Windows except
* for the separator character.
*
* /foo// --> /foo/
* /foo/./ --> /foo/
* /foo/../bar --> /bar
* /foo/../bar/ --> /bar/
* /foo/../bar/../baz --> /baz
* //foo//./bar --> /foo/bar
* /../ --> null
* ../foo --> null
* foo/bar/.. --> foo/
* foo/../../bar --> null
* foo/../bar --> bar
* //server/foo/../bar --> //server/bar
* //server/../bar --> null
* C:\foo\..\bar --> C:\bar
* C:\..\bar --> null
* ~/foo/../bar/ --> ~/bar/
* ~/../bar --> null
*
* (Note the file separator returned will be correct for Windows/Unix)
*
* @param filename the file to normalize, null returns null
* @return the normalized file, or null if invalid
*/
public static
File normalize(String filename) {
if (filename == null) {
return null;
}
String asString = doNormalize(new File(filename).getAbsolutePath(), SYSTEM_SEPARATOR, true);
if (asString == null) {
return null;
}
return new File(asString).getAbsoluteFile();
}
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Normalizes a path, removing double and single dot path steps.
*
* This method normalizes a path to a standard format.
* The input may contain separators in either Unix or Windows format.
* The output will contain separators in the format of the system.
*
* A trailing slash will be retained.
* A double slash will be merged to a single slash (but UNC names are handled).
* A single dot path segment will be removed.
* A double dot will cause that path segment and the one before to be removed.
* If the double dot has no parent path segment to work with, {@code null}
* is returned.
*
* The output will be the same on both Unix and Windows except
* for the separator character.
*
* /foo// --> /foo/
* /foo/./ --> /foo/
* /foo/../bar --> /bar
* /foo/../bar/ --> /bar/
* /foo/../bar/../baz --> /baz
* //foo//./bar --> /foo/bar
* /../ --> null
* ../foo --> null
* foo/bar/.. --> foo/
* foo/../../bar --> null
* foo/../bar --> bar
* //server/foo/../bar --> //server/bar
* //server/../bar --> null
* C:\foo\..\bar --> C:\bar
* C:\..\bar --> null
* ~/foo/../bar/ --> ~/bar/
* ~/../bar --> null
*
* (Note the file separator returned will be correct for Windows/Unix)
*
* @param file the file to normalize, null returns null
* @return the normalized file, or null if invalid
*/
public static
File normalize(File file) {
if (file == null) {
return null;
}
String asString = doNormalize(file.getAbsolutePath(), SYSTEM_SEPARATOR, true);
if (asString == null) {
return null;
}
return new File(asString).getAbsoluteFile();
}
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Normalizes a path, removing double and single dot path steps.
*
* This method normalizes a path to a standard format.
* The input may contain separators in either Unix or Windows format.
* The output will contain separators in the format specified.
*
* A trailing slash will be retained.
* A double slash will be merged to a single slash (but UNC names are handled).
* A single dot path segment will be removed.
* A double dot will cause that path segment and the one before to be removed.
* If the double dot has no parent path segment to work with, {@code null}
* is returned.
*
* The output will be the same on both Unix and Windows except
* for the separator character.
*
* /foo// --> /foo/
* /foo/./ --> /foo/
* /foo/../bar --> /bar
* /foo/../bar/ --> /bar/
* /foo/../bar/../baz --> /baz
* //foo//./bar --> /foo/bar
* /../ --> null
* ../foo --> null
* foo/bar/.. --> foo/
* foo/../../bar --> null
* foo/../bar --> bar
* //server/foo/../bar --> //server/bar
* //server/../bar --> null
* C:\foo\..\bar --> C:\bar
* C:\..\bar --> null
* ~/foo/../bar/ --> ~/bar/
* ~/../bar --> null
*
* The output will be the same on both Unix and Windows including
* the separator character.
*
* @param filename the filename to normalize, null returns null
* @param unixSeparator {@code true} if a unix separator should
* be used or {@code false} if a windows separator should be used.
* @return the normalized filename, or null if invalid
* @since 2.0
*/
public static
String normalize(String filename, boolean unixSeparator) {
char separator = unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR;
return doNormalize(filename, separator, true);
}
//-----------------------------------------------------------------------
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Normalizes a path, removing double and single dot path steps,
* and removing any final directory separator.
*
* This method normalizes a path to a standard format.
* The input may contain separators in either Unix or Windows format.
* The output will contain separators in the format of the system.
*
* A trailing slash will be removed.
* A double slash will be merged to a single slash (but UNC names are handled).
* A single dot path segment will be removed.
* A double dot will cause that path segment and the one before to be removed.
* If the double dot has no parent path segment to work with, {@code null}
* is returned.
*
* The output will be the same on both Unix and Windows except
* for the separator character.
*
* /foo// --> /foo
* /foo/./ --> /foo
* /foo/../bar --> /bar
* /foo/../bar/ --> /bar
* /foo/../bar/../baz --> /baz
* //foo//./bar --> /foo/bar
* /../ --> null
* ../foo --> null
* foo/bar/.. --> foo
* foo/../../bar --> null
* foo/../bar --> bar
* //server/foo/../bar --> //server/bar
* //server/../bar --> null
* C:\foo\..\bar --> C:\bar
* C:\..\bar --> null
* ~/foo/../bar/ --> ~/bar
* ~/../bar --> null
*
* (Note the file separator returned will be correct for Windows/Unix)
*
* @param filename the filename to normalize, null returns null
* @return the normalized filename, or null if invalid
*/
public static
String normalizeNoEndSeparator(String filename) {
return doNormalize(filename, SYSTEM_SEPARATOR, false);
}
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Normalizes a path, removing double and single dot path steps,
* and removing any final directory separator.
*
* This method normalizes a path to a standard format.
* The input may contain separators in either Unix or Windows format.
* The output will contain separators in the format specified.
*
* A trailing slash will be removed.
* A double slash will be merged to a single slash (but UNC names are handled).
* A single dot path segment will be removed.
* A double dot will cause that path segment and the one before to be removed.
* If the double dot has no parent path segment to work with, {@code null}
* is returned.
*
* The output will be the same on both Unix and Windows including
* the separator character.
*
* /foo// --> /foo
* /foo/./ --> /foo
* /foo/../bar --> /bar
* /foo/../bar/ --> /bar
* /foo/../bar/../baz --> /baz
* //foo//./bar --> /foo/bar
* /../ --> null
* ../foo --> null
* foo/bar/.. --> foo
* foo/../../bar --> null
* foo/../bar --> bar
* //server/foo/../bar --> //server/bar
* //server/../bar --> null
* C:\foo\..\bar --> C:\bar
* C:\..\bar --> null
* ~/foo/../bar/ --> ~/bar
* ~/../bar --> null
*
*
* @param filename the filename to normalize, null returns null
* @param unixSeparator {@code true} if a unix separator should
* be used or {@code false} if a windows separtor should be used.
* @return the normalized filename, or null if invalid
* @since 2.0
*/
public static
String normalizeNoEndSeparator(String filename, boolean unixSeparator) {
char separator = unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR;
return doNormalize(filename, separator, false);
}
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Internal method to perform the normalization.
*
* @param filename the filename
* @param separator The separator character to use
* @param keepSeparator true to keep the final separator
* @return the normalized filename
*/
private static
String doNormalize(String filename, char separator, boolean keepSeparator) {
if (filename == null) {
return null;
}
int size = filename.length();
if (size == 0) {
return filename;
}
int prefix = getPrefixLength(filename);
if (prefix < 0) {
return null;
}
char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy
filename.getChars(0, filename.length(), array, 0);
// fix separators throughout
char otherSeparator = separator == SYSTEM_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_SEPARATOR;
for (int i = 0; i < array.length; i++) {
if (array[i] == otherSeparator) {
array[i] = separator;
}
}
// add extra separator on the end to simplify code below
boolean lastIsDirectory = true;
if (array[size - 1] != separator) {
array[size++] = separator;
lastIsDirectory = false;
}
// adjoining slashes
for (int i = prefix + 1; i < size; i++) {
if (array[i] == separator && array[i - 1] == separator) {
System.arraycopy(array, i, array, i - 1, size - i);
size--;
i--;
}
}
// dot slash
for (int i = prefix + 1; i < size; i++) {
if (array[i] == separator && array[i - 1] == '.' &&
(i == prefix + 1 || array[i - 2] == separator)) {
if (i == size - 1) {
lastIsDirectory = true;
}
System.arraycopy(array, i + 1, array, i - 1, size - i);
size -= 2;
i--;
}
}
// double dot slash
outer:
for (int i = prefix + 2; i < size; i++) {
if (array[i] == separator && array[i - 1] == '.' && array[i - 2] == '.' &&
(i == prefix + 2 || array[i - 3] == separator)) {
if (i == prefix + 2) {
return null;
}
if (i == size - 1) {
lastIsDirectory = true;
}
int j;
for (j = i - 4; j >= prefix; j--) {
if (array[j] == separator) {
// remove b/../ from a/b/../c
System.arraycopy(array, i + 1, array, j + 1, size - i);
size -= i - j;
i = j + 1;
continue outer;
}
}
// remove a/../ from a/../c
System.arraycopy(array, i + 1, array, prefix, size - i);
size -= i + 1 - prefix;
i = prefix + 1;
}
}
if (size <= 0) { // should never be less than 0
return "";
}
if (size <= prefix) { // should never be less than prefix
return new String(array, 0, size);
}
if (lastIsDirectory && keepSeparator) {
return new String(array, 0, size); // keep trailing separator
}
return new String(array, 0, size - 1); // lose trailing separator
}
//-----------------------------------------------------------------------
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Returns the length of the filename prefix, such as C:/
or ~/
.
*
* This method will handle a file in either Unix or Windows format.
*
* The prefix length includes the first slash in the full filename
* if applicable. Thus, it is possible that the length returned is greater
* than the length of the input string.
*
* Windows:
* a\b\c.txt --> "" --> relative
* \a\b\c.txt --> "\" --> current drive absolute
* C:a\b\c.txt --> "C:" --> drive relative
* C:\a\b\c.txt --> "C:\" --> absolute
* \\server\a\b\c.txt --> "\\server\" --> UNC
*
* Unix:
* a/b/c.txt --> "" --> relative
* /a/b/c.txt --> "/" --> absolute
* ~/a/b/c.txt --> "~/" --> current user
* ~ --> "~/" --> current user (slash added)
* ~user/a/b/c.txt --> "~user/" --> named user
* ~user --> "~user/" --> named user (slash added)
*
*
* The output will be the same irrespective of the machine that the code is running on.
* ie. both Unix and Windows prefixes are matched regardless.
*
* @param filename the filename to find the prefix in, null returns -1
* @return the length of the prefix, -1 if invalid or null
*/
public static
int getPrefixLength(String filename) {
if (filename == null) {
return -1;
}
int len = filename.length();
if (len == 0) {
return 0;
}
char ch0 = filename.charAt(0);
if (ch0 == ':') {
return -1;
}
if (len == 1) {
if (ch0 == '~') {
return 2; // return a length greater than the input
}
return isSeparator(ch0) ? 1 : 0;
}
else {
if (ch0 == '~') {
int posUnix = filename.indexOf(UNIX_SEPARATOR, 1);
int posWin = filename.indexOf(WINDOWS_SEPARATOR, 1);
if (posUnix == -1 && posWin == -1) {
return len + 1; // return a length greater than the input
}
posUnix = posUnix == -1 ? posWin : posUnix;
posWin = posWin == -1 ? posUnix : posWin;
return Math.min(posUnix, posWin) + 1;
}
char ch1 = filename.charAt(1);
if (ch1 == ':') {
ch0 = Character.toUpperCase(ch0);
if (ch0 >= 'A' && ch0 <= 'Z') {
//noinspection PointlessBooleanExpression
if (len == 2 || isSeparator(filename.charAt(2)) == false) {
return 2;
}
return 3;
}
return -1;
}
else if (isSeparator(ch0) && isSeparator(ch1)) {
int posUnix = filename.indexOf(UNIX_SEPARATOR, 2);
int posWin = filename.indexOf(WINDOWS_SEPARATOR, 2);
if (posUnix == -1 && posWin == -1 || posUnix == 2 || posWin == 2) {
return -1;
}
posUnix = posUnix == -1 ? posWin : posUnix;
posWin = posWin == -1 ? posUnix : posWin;
return Math.min(posUnix, posWin) + 1;
}
else {
return isSeparator(ch0) ? 1 : 0;
}
}
}
//-----------------------------------------------------------------------
/*
* FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
* http://commons.apache.org/proper/commons-io/
* Copyright 2013 ASF
* Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck,
* Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper,
* Jeremias Maerki, Stephen Colebourne
*/
/**
* Checks if the character is a separator.
*
* @param ch the character to check
* @return true if it is a separator character
*/
private static
boolean isSeparator(char ch) {
return ch == UNIX_SEPARATOR || ch == WINDOWS_SEPARATOR;
}
/**
* Gets the extension of a file (text after the last '.')
*
* @return "" if there is no extension or fileName is null
*/
public static
String getExtension(String fileName) {
if (fileName == null) {
return "";
}
int dot = fileName.lastIndexOf('.');
if (dot > -1) {
return fileName.substring(dot + 1);
}
else {
return "";
}
}
/**
* Gets the name of a file that is before the extension (text before the last '.')
*
* @return non-null
*/
public static
String getNameWithoutExtension(final String fileName) {
int dot = fileName.lastIndexOf('.');
if (dot > -1) {
return fileName.substring(0, dot);
}
else {
return fileName;
}
}
}