mbenson 2005/01/26 09:31:04
Modified: src/main/org/apache/tools/ant/util Tag: ANT_16_BRANCH
FileUtils.java
Log:
Sync with HEAD, minus two deprecation warnings.
Revision Changes Path
No revision
No revision
1.56.2.8 +406 -294 ant/src/main/org/apache/tools/ant/util/FileUtils.java
Index: FileUtils.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/util/FileUtils.java,v
retrieving revision 1.56.2.7
retrieving revision 1.56.2.8
diff -u -r1.56.2.7 -r1.56.2.8
--- FileUtils.java 9 Mar 2004 17:01:57 -0000 1.56.2.7
+++ FileUtils.java 26 Jan 2005 17:31:04 -0000 1.56.2.8
@@ -1,5 +1,5 @@
/*
- * Copyright 2001-2004 The Apache Software Foundation
+ * Copyright 2001-2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,8 @@
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
-import java.lang.reflect.Method;
+import java.io.Writer;
+import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.CharacterIterator;
@@ -49,19 +50,25 @@
/**
* This class also encapsulates methods which allow Files to be
- * refered to using abstract path names which are translated to native
+ * referred to using abstract path names which are translated to native
* system file paths at runtime as well as copying files or setting
- * there last modification time.
+ * their last modification time.
*
* @version $Revision$
*/
public class FileUtils {
- private static Random rand = new Random(System.currentTimeMillis());
- private static Object lockReflection = new Object();
- private static java.lang.reflect.Method setLastModified = null;
- private boolean onNetWare = Os.isFamily("netware");
+ private static final FileUtils PRIMARY_INSTANCE = new FileUtils();
+
+ //get some non-crypto-grade randomness from various places.
+ private static Random rand = new Random(System.currentTimeMillis()
+ + Runtime.getRuntime().freeMemory());
+
+ private static boolean onNetWare = Os.isFamily("netware");
+ private static boolean onDos = Os.isFamily("dos");
+
+ private static final int BUF_SIZE = 8192;
// for toURI
private static boolean[] isSpecial = new boolean[256];
@@ -69,10 +76,15 @@
private static char[] escapedChar2 = new char[256];
/**
- * the granularity of timestamps under FAT
+ * The granularity of timestamps under FAT.
*/
public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000;
+ /**
+ * The granularity of timestamps under Unix.
+ */
+ public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000;
+
// stolen from FilePathToURI of the Xerces-J team
static {
@@ -106,16 +118,26 @@
}
/**
+ * Method to retrieve The FileUtils, which is shared by all users of this
+ * method.
+ * @return an instance of FileUtils.
+ * @since Ant 1.6.3
+ */
+ public static FileUtils getFileUtils() {
+ return PRIMARY_INSTANCE;
+ }
+
+ /**
* Empty constructor.
*/
protected FileUtils() {
}
/**
- * Get the URL for a file taking into account # characters
+ * Get the URL for a file taking into account # characters.
*
* @param file the file whose URL representation is required.
- * @return The FileURL value
+ * @return The FileURL value.
* @throws MalformedURLException if the URL representation cannot be
* formed.
*/
@@ -124,7 +146,7 @@
}
/**
- * Convienence method to copy a file from a source to a destination.
+ * Convenience method to copy a file from a source to a destination.
* No filtering is performed.
*
* @param sourceFile Name of file to copy from.
@@ -132,7 +154,7 @@
* @param destFile Name of file to copy to.
* Must not be <code>null</code>.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*/
public void copyFile(String sourceFile, String destFile)
throws IOException {
@@ -140,16 +162,16 @@
}
/**
- * Convienence method to copy a file from a source to a destination
+ * Convenience method to copy a file from a source to a destination
* specifying if token filtering must be used.
*
* @param sourceFile Name of file to copy from.
* Must not be <code>null</code>.
* @param destFile Name of file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*/
public void copyFile(String sourceFile, String destFile,
FilterSetCollection filters)
@@ -159,7 +181,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used and if
* source files may overwrite newer destination files.
*
@@ -167,11 +189,11 @@
* Must not be <code>null</code>.
* @param destFile Name of file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*/
public void copyFile(String sourceFile, String destFile,
FilterSetCollection filters,
boolean overwrite) throws IOException {
@@ -180,7 +202,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* source files may overwrite newer destination files and the
* last modified time of <code>destFile</code> file should be made equal
@@ -190,14 +212,14 @@
* Must not be <code>null</code>.
* @param destFile Name of file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
* @param preserveLastModified Whether or not the last modified time of
* the resulting file should be set to that
* of the source file.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*/
public void copyFile(String sourceFile, String destFile,
FilterSetCollection filters,
boolean overwrite, boolean preserveLastModified)
@@ -207,7 +229,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* source files may overwrite newer destination files and the
* last modified time of <code>destFile</code> file should be made equal
@@ -217,7 +239,7 @@
* Must not be <code>null</code>.
* @param destFile Name of file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
* @param preserveLastModified Whether or not the last modified time of
@@ -225,7 +247,7 @@
* of the source file.
* @param encoding the encoding used to read and write the files.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*
* @since Ant 1.5
*/
@@ -238,7 +260,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* filter chains must be used, if source files may overwrite
* newer destination files and the last modified time of
@@ -249,7 +271,7 @@
* Must not be <code>null</code>.
* @param destFile Name of file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param filterChains filterChains to apply during the copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
@@ -257,9 +279,9 @@
* the resulting file should be set to that
* of the source file.
* @param encoding the encoding used to read and write the files.
- * @param project the project instance
+ * @param project the project instance.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*
* @since Ant 1.5
*/
@@ -274,7 +296,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* filter chains must be used, if source files may overwrite
* newer destination files and the last modified time of
@@ -285,7 +307,7 @@
* Must not be <code>null</code>.
* @param destFile Name of file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param filterChains filterChains to apply during the copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
@@ -294,9 +316,9 @@
* of the source file.
* @param inputEncoding the encoding used to read the files.
* @param outputEncoding the encoding used to write the files.
- * @param project the project instance
+ * @param project the project instance.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*
* @since Ant 1.6
*/
@@ -312,7 +334,7 @@
}
/**
- * Convienence method to copy a file from a source to a destination.
+ * Convenience method to copy a file from a source to a destination.
* No filtering is performed.
*
* @param sourceFile the file to copy from.
@@ -320,23 +342,23 @@
* @param destFile the file to copy to.
* Must not be <code>null</code>.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*/
public void copyFile(File sourceFile, File destFile) throws IOException {
copyFile(sourceFile, destFile, null, false, false);
}
/**
- * Convienence method to copy a file from a source to a destination
+ * Convenience method to copy a file from a source to a destination
* specifying if token filtering must be used.
*
* @param sourceFile the file to copy from.
* Must not be <code>null</code>.
* @param destFile the file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*/
public void copyFile(File sourceFile, File destFile, FilterSetCollection
filters)
throws IOException {
@@ -344,7 +366,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used and if
* source files may overwrite newer destination files.
*
@@ -352,11 +374,11 @@
* Must not be <code>null</code>.
* @param destFile the file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*/
public void copyFile(File sourceFile, File destFile, FilterSetCollection
filters,
boolean overwrite) throws IOException {
@@ -364,7 +386,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* source files may overwrite newer destination files and the
* last modified time of <code>destFile</code> file should be made equal
@@ -374,14 +396,14 @@
* Must not be <code>null</code>.
* @param destFile the file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
* @param preserveLastModified Whether or not the last modified time of
* the resulting file should be set to that
* of the source file.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*/
public void copyFile(File sourceFile, File destFile, FilterSetCollection
filters,
boolean overwrite, boolean preserveLastModified)
@@ -391,7 +413,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* source files may overwrite newer destination files, the last
* modified time of <code>destFile</code> file should be made
@@ -402,7 +424,7 @@
* Must not be <code>null</code>.
* @param destFile the file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
* @param preserveLastModified Whether or not the last modified time of
@@ -410,7 +432,7 @@
* of the source file.
* @param encoding the encoding used to read and write the files.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*
* @since Ant 1.5
*/
@@ -423,7 +445,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* filter chains must be used, if source files may overwrite
* newer destination files and the last modified time of
@@ -434,7 +456,7 @@
* Must not be <code>null</code>.
* @param destFile the file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param filterChains filterChains to apply during the copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
@@ -442,9 +464,9 @@
* the resulting file should be set to that
* of the source file.
* @param encoding the encoding used to read and write the files.
- * @param project the project instance
+ * @param project the project instance.
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*
* @since Ant 1.5
*/
@@ -458,7 +480,7 @@
}
/**
- * Convienence method to copy a file from a source to a
+ * Convenience method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* filter chains must be used, if source files may overwrite
* newer destination files and the last modified time of
@@ -469,7 +491,7 @@
* Must not be <code>null</code>.
* @param destFile the file to copy to.
* Must not be <code>null</code>.
- * @param filters the collection of filters to apply to this copy
+ * @param filters the collection of filters to apply to this copy.
* @param filterChains filterChains to apply during the copy.
* @param overwrite Whether or not the destination file should be
* overwritten if it already exists.
@@ -478,10 +500,10 @@
* of the source file.
* @param inputEncoding the encoding used to read the files.
* @param outputEncoding the encoding used to write the files.
- * @param project the project instance
+ * @param project the project instance.
*
*
- * @throws IOException if the copying fails
+ * @throws IOException if the copying fails.
*
* @since Ant 1.6
*/
@@ -498,23 +520,19 @@
if (destFile.exists() && destFile.isFile()) {
destFile.delete();
}
-
// ensure that parent dir of dest file exists!
// not using getParentFile method to stay 1.1 compat
- File parent = getParentFile(destFile);
+ File parent = destFile.getParentFile();
if (parent != null && !parent.exists()) {
parent.mkdirs();
}
-
final boolean filterSetsAvailable = (filters != null
&& filters.hasFilters());
final boolean filterChainsAvailable = (filterChains != null
&& filterChains.size() >
0);
-
if (filterSetsAvailable) {
BufferedReader in = null;
BufferedWriter out = null;
-
try {
if (inputEncoding == null) {
in = new BufferedReader(new FileReader(sourceFile));
@@ -524,7 +542,6 @@
inputEncoding);
in = new BufferedReader(isr);
}
-
if (outputEncoding == null) {
out = new BufferedWriter(new FileWriter(destFile));
} else {
@@ -533,17 +550,15 @@
outputEncoding);
out = new BufferedWriter(osw);
}
-
if (filterChainsAvailable) {
ChainReaderHelper crh = new ChainReaderHelper();
- crh.setBufferSize(8192);
+ crh.setBufferSize(BUF_SIZE);
crh.setPrimaryReader(in);
crh.setFilterChains(filterChains);
crh.setProject(project);
Reader rdr = crh.getAssembledReader();
in = new BufferedReader(rdr);
}
-
LineTokenizer lineTokenizer = new LineTokenizer();
lineTokenizer.setIncludeDelims(true);
String newline = null;
@@ -560,12 +575,8 @@
line = lineTokenizer.getToken(in);
}
} finally {
- if (out != null) {
- out.close();
- }
- if (in != null) {
- in.close();
- }
+ close(out);
+ close(in);
}
} else if (filterChainsAvailable
|| (inputEncoding != null
@@ -573,7 +584,6 @@
|| (inputEncoding == null && outputEncoding != null))
{
BufferedReader in = null;
BufferedWriter out = null;
-
try {
if (inputEncoding == null) {
in = new BufferedReader(new FileReader(sourceFile));
@@ -584,7 +594,6 @@
new FileInputStream(sourceFile),
inputEncoding));
}
-
if (outputEncoding == null) {
out = new BufferedWriter(new FileWriter(destFile));
} else {
@@ -594,17 +603,16 @@
new FileOutputStream(destFile),
outputEncoding));
}
-
if (filterChainsAvailable) {
ChainReaderHelper crh = new ChainReaderHelper();
- crh.setBufferSize(8192);
+ crh.setBufferSize(BUF_SIZE);
crh.setPrimaryReader(in);
crh.setFilterChains(filterChains);
crh.setProject(project);
Reader rdr = crh.getAssembledReader();
in = new BufferedReader(rdr);
}
- char[] buffer = new char[1024 * 8];
+ char[] buffer = new char[BUF_SIZE];
while (true) {
int nRead = in.read(buffer, 0, buffer.length);
if (nRead == -1) {
@@ -612,13 +620,9 @@
}
out.write(buffer, 0, nRead);
}
- } finally {
- if (out != null) {
- out.close();
- }
- if (in != null) {
- in.close();
- }
+ } finally {
+ close(out);
+ close(in);
}
} else {
FileInputStream in = null;
@@ -627,22 +631,17 @@
in = new FileInputStream(sourceFile);
out = new FileOutputStream(destFile);
- byte[] buffer = new byte[8 * 1024];
+ byte[] buffer = new byte[BUF_SIZE];
int count = 0;
do {
out.write(buffer, 0, count);
count = in.read(buffer, 0, buffer.length);
} while (count != -1);
} finally {
- if (out != null) {
- out.close();
- }
- if (in != null) {
- in.close();
- }
+ close(out);
+ close(in);
}
}
-
if (preserveLastModified) {
setFileLastModified(destFile, sourceFile.lastModified());
}
@@ -650,63 +649,19 @@
}
/**
- * see whether we have a setLastModified method in File and return it.
- *
- * @return a method to setLastModified.
- */
- protected final Method getSetLastModified() {
- if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
- return null;
- }
- synchronized (lockReflection) {
- if (setLastModified == null) {
- try {
- setLastModified =
- java.io.File.class.getMethod("setLastModified",
- new Class[]
{Long.TYPE});
- } catch (NoSuchMethodException nse) {
- throw new BuildException("File.setlastModified not in
JDK > 1.1?",
- nse);
- }
- }
- }
- return setLastModified;
- }
-
- /**
- * Calls File.setLastModified(long time) in a Java 1.1 compatible way.
+ * Calls File.setLastModified(long time). Originally written to
+ * to dynamically bind to that call on Java1.2+.
*
* @param file the file whose modified time is to be set
* @param time the time to which the last modified time is to be set.
- *
- * @throws BuildException if the time cannot be set.
+ * if this is -1, the current time is used.
*/
- public void setFileLastModified(File file, long time)
- throws BuildException {
- if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
- return;
- }
- Long[] times = new Long[1];
- if (time < 0) {
- times[0] = new Long(System.currentTimeMillis());
- } else {
- times[0] = new Long(time);
- }
-
- try {
- getSetLastModified().invoke(file, times);
- } catch (java.lang.reflect.InvocationTargetException ite) {
- Throwable nested = ite.getTargetException();
- throw new BuildException("Exception setting the modification
time "
- + "of " + file, nested);
- } catch (Throwable other) {
- throw new BuildException("Exception setting the modification
time "
- + "of " + file, other);
- }
+ public void setFileLastModified(File file, long time) {
+ file.setLastModified((time < 0) ? System.currentTimeMillis() : time);
}
/**
- * Interpret the filename as a file relative to the given file -
+ * Interpret the filename as a file relative to the given file
* unless the filename already represents an absolute filename.
*
* @param file the "reference" file for relative paths. This
@@ -715,7 +670,7 @@
* of /). If it is null, this call is equivalent to
* <code>new java.io.File(filename)</code>.
*
- * @param filename a file name
+ * @param filename a file name.
*
* @return an absolute file that doesn't contain "./" or
* "../" sequences and uses the correct separator for
@@ -726,34 +681,18 @@
.replace('\\', File.separatorChar);
// deal with absolute files
- if (!onNetWare) {
- if (filename.startsWith(File.separator)
- || (filename.length() >= 2
- && Character.isLetter(filename.charAt(0))
- && filename.charAt(1) == ':')) {
- return normalize(filename);
- }
- } else {
- // the assumption that the : will appear as the second character
in
- // the path name breaks down when NetWare is a supported
platform.
- // Netware volumes are of the pattern: "data:\"
- int colon = filename.indexOf(":");
- if (filename.startsWith(File.separator)
- || (colon > -1)) {
- return normalize(filename);
- }
+ if (isAbsolutePath(filename)) {
+ return normalize(filename);
}
-
if (file == null) {
return new File(filename);
}
-
File helpFile = new File(file.getAbsolutePath());
StringTokenizer tok = new StringTokenizer(filename, File.separator);
while (tok.hasMoreTokens()) {
String part = tok.nextToken();
if (part.equals("..")) {
- helpFile = getParentFile(helpFile);
+ helpFile = helpFile.getParentFile();
if (helpFile == null) {
String msg = "The file or path you specified ("
+ filename + ") is invalid relative to "
@@ -766,25 +705,46 @@
helpFile = new File(helpFile, part);
}
}
-
return new File(helpFile.getAbsolutePath());
}
/**
- * "normalize" the given absolute path.
+ * Verifies if the filename represents is an absolute path.
+ * @param filename the file name to be checked for being an absolute
path.
+ * @return true if the filename represents an absolute path.
+ */
+ private static boolean isAbsolutePath(String filename) {
+ if (filename.startsWith(File.separator)) {
+ // common for all os
+ return true;
+ }
+ if (onDos && filename.length() >= 2
+ && Character.isLetter(filename.charAt(0))
+ && filename.charAt(1) == ':') {
+ // Actually on windows the : must be followed by a \ for
+ // the path to be absolute, else the path is relative
+ // to the current working directory on that drive.
+ // (Every drive may have another current working directory)
+ return true;
+ }
+ return (onNetWare && filename.indexOf(":") > -1);
+ }
+
+ /**
+ * "Normalize" the given absolute path.
*
* <p>This includes:
* <ul>
* <li>Uppercase the drive letter if there is one.</li>
* <li>Remove redundant slashes after the drive spec.</li>
- * <li>resolve all ./, .\, ../ and ..\ sequences.</li>
+ * <li>Resolve all ./, .\, ../ and ..\ sequences.</li>
* <li>DOS style paths that start with a drive letter will have
* \ as the separator.</li>
* </ul>
- * Unlike <code>File#getCanonicalPath()</code> it specifically doesn't
- * resolve symbolic links.
+ * Unlike <code>File#getCanonicalPath()</code> this method
+ * specifically does not resolve symbolic links.
*
- * @param path the path to be normalized
+ * @param path the path to be normalized.
* @return the normalized version of the path.
*
* @throws java.lang.NullPointerException if the file path is
@@ -799,26 +759,14 @@
// make sure we are dealing with an absolute path
int colon = path.indexOf(":");
- if (!onNetWare) {
- if (!path.startsWith(File.separator)
- && !(path.length() >= 2
- && Character.isLetter(path.charAt(0))
- && colon == 1)) {
- String msg = path + " is not an absolute path";
- throw new BuildException(msg);
- }
- } else {
- if (!path.startsWith(File.separator)
- && (colon == -1)) {
- String msg = path + " is not an absolute path";
- throw new BuildException(msg);
- }
+ if (!isAbsolutePath(path)) {
+ String msg = path + " is not an absolute path";
+ throw new BuildException(msg);
}
-
boolean dosWithDrive = false;
String root = null;
// Eliminate consecutive slashes after the drive spec
- if ((!onNetWare && path.length() >= 2
+ if ((onDos && path.length() >= 2
&& Character.isLetter(path.charAt(0))
&& path.charAt(1) == ':')
|| (onNetWare && colon > -1)) {
@@ -845,7 +793,6 @@
}
}
path = sbPath.toString().replace('\\', File.separatorChar);
-
} else {
if (path.length() == 1) {
root = File.separator;
@@ -859,7 +806,6 @@
path = path.substring(1);
}
}
-
Stack s = new Stack();
s.push(root);
StringTokenizer tok = new StringTokenizer(path, File.separator);
@@ -877,7 +823,6 @@
s.push(thisToken);
}
}
-
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.size(); i++) {
if (i > 1) {
@@ -887,8 +832,6 @@
}
sb.append(s.elementAt(i));
}
-
-
path = sb.toString();
if (dosWithDrive) {
path = path.replace('/', '\\');
@@ -912,8 +855,8 @@
String name = f.getName();
boolean isAbsolute = path.charAt(0) == File.separatorChar;
// treat directories specified using .DIR syntax as files
- boolean isDirectory = f.isDirectory() &&
- !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4);
+ boolean isDirectory = f.isDirectory()
+ && !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4);
String device = null;
StringBuffer directory = null;
@@ -949,9 +892,9 @@
if (!isAbsolute && directory != null) {
directory.insert(0, '.');
}
- osPath = ((device != null) ? device + ":" : "") +
- ((directory != null) ? "[" + directory + "]" : "") +
- ((file != null) ? file : "");
+ osPath = ((device != null) ? device + ":" : "")
+ + ((directory != null) ? "[" + directory + "]" : "")
+ + ((file != null) ? file : "");
return osPath;
}
@@ -961,16 +904,17 @@
* <p>The file denoted by the returned abstract pathname did not
* exist before this method was invoked, any subsequent invocation
* of this method will yield a different file name.</p>
- *
- * <p>This method is different to File.createTempFile of JDK 1.2
- * as it doesn't create the file itself.
- * It uses the location pointed to by java.io.tmpdir
- * when the parentDir attribute is
- * null.</p>
- *
- * @param parentDir Directory to create the temporary file in -
- * current working directory will be assumed if this parameter is
- * null.
+ * <p>
+ * The filename is prefixNNNNNsuffix where NNNN is a random number.
+ * </p>
+ * <p>This method is different from File.createTempFile() of JDK 1.2
+ * as it doesn't create the file itself. It uses the location pointed
+ * to by java.io.tmpdir when the parentDir attribute is null.</p>
+ *
+ * @param prefix prefix before the random number.
+ * @param suffix file extension; include the '.'.
+ * @param parentDir Directory to create the temporary file in;
+ * java.io.tmpdir used if not specified.
*
* @return a File reference to the new temporary file.
* @since ant 1.5
@@ -996,40 +940,65 @@
/**
* Compares the contents of two files.
*
- * <p>simple but sub-optimal comparision algorithm. written for
- * working rather than fast. Better would be a block read into
- * buffers followed by long comparisions apart from the final 1-7
- * bytes.</p>
- *
* @param f1 the file whose content is to be compared.
* @param f2 the other file whose content is to be compared.
*
* @return true if the content of the files is the same.
*
* @throws IOException if the files cannot be read.
- *
- * @since 1.9
*/
public boolean contentEquals(File f1, File f2) throws IOException {
+ return contentEquals(f1, f2, false);
+ }
+
+ /**
+ * Compares the contents of two files.
+ *
+ * @param f1 the file whose content is to be compared.
+ * @param f2 the other file whose content is to be compared.
+ * @param textfile true if the file is to be treated as a text file and
+ * differences in kind of line break are to be ignored.
+ *
+ * @return true if the content of the files is the same.
+ *
+ * @throws IOException if the files cannot be read.
+ * @since Ant 1.6.3
+ */
+ public boolean contentEquals(File f1, File f2, boolean textfile) throws
IOException {
if (f1.exists() != f2.exists()) {
return false;
}
-
if (!f1.exists()) {
// two not existing files are equal
return true;
}
-
+ // should the following two be switched? If f1 and f2 refer to the
same file,
+ // isn't their content equal regardless of whether that file is a
directory?
if (f1.isDirectory() || f2.isDirectory()) {
// don't want to compare directory contents for now
return false;
}
-
if (fileNameEquals(f1, f2)) {
// same filename => true
return true;
}
+ return textfile ? textEquals(f1, f2) : binaryEquals(f1, f2);
+ }
+ /**
+ * Binary compares the contents of two files.
+ * <p>
+ * simple but sub-optimal comparision algorithm. written for working
+ * rather than fast. Better would be a block read into buffers followed
+ * by long comparisions apart from the final 1-7 bytes.
+ * </p>
+ *
+ * @param f1 the file whose content is to be compared.
+ * @param f2 the other file whose content is to be compared.
+ * @return true if the content of the files is the same.
+ * @throws IOException if the files cannot be read.
+ */
+ private boolean binaryEquals(File f1, File f2) throws IOException {
if (f1.length() != f2.length()) {
// different size =>false
return false;
@@ -1053,61 +1022,76 @@
}
return true;
} finally {
- if (in1 != null) {
- try {
- in1.close();
- } catch (IOException e) {
- // ignore
+ close(in1);
+ close(in2);
+ }
+ }
+
+ /**
+ * Text compares the contents of two files.
+ *
+ * Ignores different kinds of line endings.
+ *
+ * @param f1 the file whose content is to be compared.
+ * @param f2 the other file whose content is to be compared.
+ * @return true if the content of the files is the same.
+ * @throws IOException if the files cannot be read.
+ */
+ private boolean textEquals(File f1, File f2) throws IOException {
+ BufferedReader in1 = null;
+ BufferedReader in2 = null;
+ try {
+ in1 = new BufferedReader(new FileReader(f1));
+ in2 = new BufferedReader(new FileReader(f2));
+
+ String expected = in1.readLine();
+ while (expected != null) {
+ if (!expected.equals(in2.readLine())) {
+ return false;
}
+ expected = in1.readLine();
}
- if (in2 != null) {
- try {
- in2.close();
- } catch (IOException e) {
- // ignore
- }
+ if (in2.readLine() != null) {
+ return false;
}
+ return true;
+ } finally {
+ close(in1);
+ close(in2);
}
}
/**
- * Emulation of File.getParentFile for JDK 1.1
- *
- *
+ * This was originally an emulation of [EMAIL PROTECTED]
File#getParentFile} for JDK 1.1,
+ * but it is now implemented using that method (Ant 1.6.3 onwards).
* @param f the file whose parent is required.
* @return the given file's parent, or null if the file does not have a
* parent.
* @since 1.10
*/
public File getParentFile(File f) {
- if (f != null) {
- String p = f.getParent();
- if (p != null) {
- return new File(p);
- }
- }
- return null;
+ return (f == null) ? null : f.getParentFile();
}
/**
- * Read from reader till EOF
+ * Read from reader till EOF.
* @param rdr the reader from which to read.
- * @return the contents read out of the given reader
+ * @return the contents read out of the given reader.
*
* @throws IOException if the contents could not be read out from the
* reader.
*/
public static final String readFully(Reader rdr) throws IOException {
- return readFully(rdr, 8192);
+ return readFully(rdr, BUF_SIZE);
}
/**
- * Read from reader till EOF
+ * Read from reader till EOF.
*
* @param rdr the reader from which to read.
- * @param bufferSize the buffer size to use when reading
+ * @param bufferSize the buffer size to use when reading.
*
- * @return the contents read out of the given reader
+ * @return the contents read out of the given reader.
*
* @throws IOException if the contents could not be read out from the
* reader.
@@ -1120,73 +1104,68 @@
}
final char[] buffer = new char[bufferSize];
int bufferLength = 0;
- String text = null;
StringBuffer textBuffer = null;
while (bufferLength != -1) {
bufferLength = rdr.read(buffer);
- if (bufferLength != -1) {
- if (textBuffer == null) {
- textBuffer = new StringBuffer(
- new String(buffer, 0,
bufferLength));
- } else {
- textBuffer.append(new String(buffer, 0, bufferLength));
- }
+ if (bufferLength > 0) {
+ textBuffer = (textBuffer == null) ? new StringBuffer() :
textBuffer;
+ textBuffer.append(new String(buffer, 0, bufferLength));
}
}
- if (textBuffer != null) {
- text = textBuffer.toString();
- }
- return text;
+ return (textBuffer == null) ? null : textBuffer.toString();
}
/**
- * Emulation of File.createNewFile for JDK 1.1.
+ * This was originally an emulation of File.createNewFile for JDK 1.1,
+ * but it is now implemented using that method (Ant 1.6.3 onwards).
*
- * <p>This method does <strong>not</strong> guarantee that the
- * operation is atomic.</p>
+ * <p>This method has historically <strong>not</strong> guaranteed that
the
+ * operation was atomic. In its current implementation it is.
*
- * @param f the file to be created
+ * @param f the file to be created.
* @return true if the file did not exist already.
+ * @throws IOException on error.
* @since Ant 1.5
*/
public boolean createNewFile(File f) throws IOException {
- if (f != null) {
- if (f.exists()) {
- return false;
- }
-
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(f);
- fos.write(new byte[0]);
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
+ return f.createNewFile();
+ }
- return true;
+ /**
+ * Create a new file, optionally creating parent directories.
+ *
+ * @param f the file to be created.
+ * @param mkdirs <code>boolean</code> whether to create parent
directories.
+ * @return true if the file did not exist already.
+ * @throws IOException on error.
+ * @since Ant 1.6.3
+ */
+ public boolean createNewFile(File f, boolean mkdirs) throws IOException {
+ File parent = f.getParentFile();
+ if (mkdirs && !(parent.exists())) {
+ parent.mkdirs();
}
- return false;
+ return f.createNewFile();
}
/**
* Checks whether a given file is a symbolic link.
*
* <p>It doesn't really test for symbolic links but whether the
- * canonical and absolute paths of the file are identical - this
+ * canonical and absolute paths of the file are identical--this
* may lead to false positives on some platforms.</p>
*
* @param parent the parent directory of the file to test
* @param name the name of the file to test.
*
* @return true if the file is a symbolic link.
+ * @throws IOException on error.
* @since Ant 1.5
*/
public boolean isSymbolicLink(File parent, String name)
throws IOException {
- File resolvedParent = new File(parent.getCanonicalPath());
- File toTest = new File(resolvedParent, name);
+ File toTest = new File(((parent == null)
+ ? null : parent.getCanonicalPath()), name);
return !toTest.getAbsolutePath().equals(toTest.getCanonicalPath());
}
@@ -1197,7 +1176,7 @@
* @param path The path to remove from, must not be null, must be
absolute.
*
* @return path's normalized absolute if it doesn't start with
- * leading, path's path with leading's path removed otherwise.
+ * leading; path's path with leading's path removed otherwise.
*
* @since Ant 1.5
*/
@@ -1213,12 +1192,7 @@
if (!l.endsWith(File.separator)) {
l += File.separator;
}
-
- if (p.startsWith(l)) {
- return p.substring(l.length());
- } else {
- return p;
- }
+ return (p.startsWith(l)) ? p.substring(l.length()) : p;
}
/**
@@ -1229,7 +1203,7 @@
*
* <p>This code doesn't handle non-ASCII characters properly.</p>
*
- * @param path the path in the local file system
+ * @param path the path in the local file system.
* @return the URI version of the local path.
* @since Ant 1.6
*/
@@ -1246,7 +1220,6 @@
if (!path.startsWith(File.separator)) {
sb.append("/");
}
-
} catch (BuildException e) {
// relative path
}
@@ -1321,13 +1294,13 @@
* <code>from</code>, which involves deleting <code>from</code> as
* well.</p>
*
+ * @param from the file to move.
+ * @param to the new file name.
+ *
* @throws IOException if anything bad happens during this
* process. Note that <code>to</code> may have been deleted
* already when this happens.
*
- * @param from the file to move
- * @param to the new file name
- *
* @since Ant 1.6
*/
public void rename(File from, File to) throws IOException {
@@ -1335,13 +1308,11 @@
throw new IOException("Failed to delete " + to
+ " while trying to rename " + from);
}
-
- File parent = getParentFile(to);
+ File parent = to.getParentFile();
if (parent != null && !parent.exists() && !parent.mkdirs()) {
throw new IOException("Failed to create directory " + parent
+ " while trying to rename " + from);
}
-
if (!from.renameTo(to)) {
copyFile(from, to);
if (!from.delete()) {
@@ -1351,11 +1322,152 @@
}
}
+ /**
+ * Get the granularity of file timestamps.
+ * The choice is made based on OS, which is incorrect--it should really
be
+ * by filesystem. We do not have an easy way to probe for file systems,
+ * however.
+ * @return the difference, in milliseconds, which two file timestamps
must have
+ * in order for the two files to be given a creation order.
+ */
public long getFileTimestampGranularity() {
- if (Os.isFamily("dos")) {
- return FAT_FILE_TIMESTAMP_GRANULARITY;
- } else {
- return 0;
+ return onDos
+ ? FAT_FILE_TIMESTAMP_GRANULARITY :
UNIX_FILE_TIMESTAMP_GRANULARITY;
+ }
+
+ /**
+ * Returns true if the source is older than the dest.
+ * If the dest file does not exist, then the test returns false; it is
+ * implicitly not up do date.
+ * @param source source file (should be the older).
+ * @param dest dest file (should be the newer).
+ * @param granularity an offset added to the source time.
+ * @return true if the source is older than the dest after accounting
+ * for granularity.
+ * @since Ant 1.6.3
+ */
+ public boolean isUpToDate(File source, File dest, long granularity) {
+ //do a check for the destination file existing
+ if (!dest.exists()) {
+ //if it does not, then the file is not up to date.
+ return false;
+ }
+ long sourceTime = source.lastModified();
+ long destTime = dest.lastModified();
+ return isUpToDate(sourceTime, destTime, granularity);
+ }
+
+
+ /**
+ * Returns true if the source is older than the dest.
+ * @param source source file (should be the older).
+ * @param dest dest file (should be the newer).
+ * @return true if the source is older than the dest, taking the
granularity into account.
+ * @since Ant 1.6.3
+ */
+ public boolean isUpToDate(File source, File dest) {
+ return isUpToDate(source, dest, getFileTimestampGranularity());
+ }
+
+ /**
+ * Compare two timestamps for being up to date using
+ * the specified granularity.
+ *
+ * @param sourceTime timestamp of source file.
+ * @param destTime timestamp of dest file.
+ * @param granularity os/filesys granularity.
+ * @return true if the dest file is considered up to date.
+ */
+ public boolean isUpToDate(long sourceTime, long destTime, long
granularity) {
+ if (destTime == -1) {
+ return false;
+ }
+ return destTime >= sourceTime + granularity;
+ }
+
+ /**
+ * Compare two timestamps for being up to date using the
+ * current granularity.
+ *
+ * @param sourceTime timestamp of source file.
+ * @param destTime timestamp of dest file.
+ * @return true if the dest file is considered up to date.
+ */
+ public boolean isUpToDate(long sourceTime, long destTime) {
+ return isUpToDate(sourceTime, destTime,
getFileTimestampGranularity());
+ }
+
+ /**
+ * Close a Writer without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ * @param device output writer, can be null.
+ */
+ public static void close(Writer device) {
+ if (device != null) {
+ try {
+ device.close();
+ } catch (IOException ioex) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Close a stream without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ *
+ * @param device Reader, can be null.
+ */
+ public static void close(Reader device) {
+ if (device != null) {
+ try {
+ device.close();
+ } catch (IOException ioex) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Close a stream without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ *
+ * @param device stream, can be null.
+ */
+ public static void close(OutputStream device) {
+ if (device != null) {
+ try {
+ device.close();
+ } catch (IOException ioex) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Close a stream without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ *
+ * @param device stream, can be null.
+ */
+ public static void close(InputStream device) {
+ if (device != null) {
+ try {
+ device.close();
+ } catch (IOException ioex) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Delete the file with [EMAIL PROTECTED] File#delete()} if the argument
is not null.
+ * Do nothing on a null argument.
+ * @param file file to delete.
+ */
+ public static void delete(File file) {
+ if (file != null) {
+ file.delete();
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]