-FileUtils now uses close to close inputstreams inside itself

-added new private method to use java.nio memory mapped files for
contentEquals method (this implementation doesn't care how large the
files are, it simply tries to map the entire file, perhaps it would be
better to check file size first and to use the older contentEquals when
files are large).

Kev
Index: FileUtils.java
===================================================================
RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/util/FileUtils.java,v
retrieving revision 1.77
diff -u -r1.77 FileUtils.java
--- FileUtils.java	11 Dec 2004 22:43:04 -0000	1.77
+++ FileUtils.java	13 Dec 2004 06:29:00 -0000
@@ -22,18 +22,22 @@
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.RandomAccessFile;
 import java.io.Reader;
 import java.io.Writer;
-import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
 import java.text.CharacterIterator;
 import java.text.DecimalFormat;
 import java.text.StringCharacterIterator;
@@ -41,12 +45,13 @@
 import java.util.Stack;
 import java.util.StringTokenizer;
 import java.util.Vector;
+
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.filters.util.ChainReaderHelper;
+import org.apache.tools.ant.launch.Locator;
 import org.apache.tools.ant.taskdefs.condition.Os;
 import org.apache.tools.ant.types.FilterSetCollection;
-import org.apache.tools.ant.launch.Locator;
 
 /**
  * This class also encapsulates methods which allow Files to be
@@ -819,15 +824,16 @@
         Stack s = new Stack();
         s.push(root);
         StringTokenizer tok = new StringTokenizer(path, File.separator);
+        int stackSize = s.size();
         while (tok.hasMoreTokens()) {
             String thisToken = tok.nextToken();
             if (".".equals(thisToken)) {
                 continue;
             } else if ("..".equals(thisToken)) {
-                if (s.size() < 2) {
-                    throw new BuildException("Cannot resolve path " + orig);
-                } else {
+                if (stackSize > 2) {
                     s.pop();
+                } else {
+                    throw new BuildException("Cannot resolve path " + orig);
                 }
             } else { // plain component
                 s.push(thisToken);
@@ -835,7 +841,7 @@
         }
 
         StringBuffer sb = new StringBuffer();
-        for (int i = 0; i < s.size(); i++) {
+        for (int i = 0; i < stackSize; i++) {
             if (i > 1) {
                 // not before the filesystem root and not after it, since root
                 // already contains one
@@ -993,7 +999,18 @@
             // different size =>false
             return false;
         }
-
+        
+        /* If we have Java => 1.4, we can use NIO
+         * This buffer comparison simply maps the entire file into memory,
+         * it's not concerned with memory usage - for large files this
+         * may cause problems         
+         */
+        if (JavaEnvUtils.getJavaVersion().equals(JavaEnvUtils.JAVA_1_4)
+                ||JavaEnvUtils.getJavaVersion().equals(JavaEnvUtils.JAVA_1_5)
+                ) {
+            return bufferEquals(f1, f2);
+        }
+        
         InputStream in1 = null;
         InputStream in2 = null;
         try {
@@ -1012,21 +1029,39 @@
             }
             return true;
         } finally {
-            if (in1 != null) {
-                try {
-                    in1.close();
-                } catch (IOException e) {
-                    // ignore
-                }
-            }
-            if (in2 != null) {
-                try {
-                    in2.close();
-                } catch (IOException e) {
-                    // ignore
-                }
+            close(in1);
+            close(in2);
+        }
+    }
+
+    /**
+     * Uses java.nio packages to compare the contents of two files.
+     * Each file is read into memory and a byte buffer is created.
+     * As soon as a byte is different the method returns.
+     * @param f1 the first file to compare
+     * @param f2 the file to compare with
+     * @return true if files are identical, false otherwise
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    private boolean bufferEquals(File f1, File f2) throws FileNotFoundException, IOException {
+        FileChannel compareeChannel = new RandomAccessFile(f1, "r").getChannel();
+        FileChannel comparerChannel = new RandomAccessFile(f2, "r").getChannel();
+        
+        ByteBuffer compareeBuf = compareeChannel.map(FileChannel.MapMode.READ_ONLY, 0, (int)compareeChannel.size());
+        ByteBuffer comparerBuf = comparerChannel.map(FileChannel.MapMode.READ_ONLY, 0, (int)comparerChannel.size());
+        
+        compareeChannel.close();
+        comparerChannel.close();
+        
+        byte[] toCompare = compareeBuf.array();
+        byte[] compareAgainst = comparerBuf.array();
+        for (int i=0; i< toCompare.length; i++) {
+            if(toCompare[i] != compareAgainst[i]) {
+                return false;
             }
         }
+        return true;
     }
 
     /**

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to