JDK-5036988 : sun.awt.shell.ShellFolder should be a public class in java.io
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 1.4.2
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2004-04-23
  • Updated: 2009-02-16
  • Resolved: 2009-02-16
Related Reports
Duplicate :  
Description
Name: jl125535			Date: 04/23/2004


A DESCRIPTION OF THE REQUEST :
ShellFolder seems to outperform java.io.File by quite a margin. It would be very nice to have this as a public API for general use.

The inefficiency in java.io.File is from requerying the file system per bit of information asked for (eg exists, isDirectory, isHidden etc..)

It would be nice to have an API that doesn't guarantee up-to-dateness of this information in exchange for speed. The obvious workaround of writing this yourself isn't as efficient as it could be because caching exists() and isDirectory() individually still queries the filesystem twice, when instead it could get this information once in one go and cache that.

(FileSnapshot does this below by using the non-public java.io.FileSystem class directly)

Ideally, on operating systems that allow this (I don't know if there are any) then you could collate *all* information at the same time - ie the boolean attributes accessible via the FileSystem class and things like the last modified time, length of the file etc.. (checksum would be nice if available..)

JSR203 may cover some of this functionality

JUSTIFICATION :
File access is extremely important for lots of applications - especially power tool like applications

I've put this as "Difficult to make progress" as severity because without it (or the workaround) java is way behind technologies that allow more flexible file access, for this class of application


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
File access is slower than native applications
ACTUAL -
File access is comparable to/same as native applications

CUSTOMER SUBMITTED WORKAROUND :
You can use reflection to safely gain access to the ShellFolder class on the subclass of JVMs that have sun.awt.shell.ShellFolder in the class pool at run-time, and fall back to normal behaviour otherwise


import java.io.*;
import java.lang.reflect.*;

public final class FileTricks {
   private static Class cShellFolder, cShellFolderManager;
   private static Constructor ctrShellFolderManager;
   private static Method mCreateShellFolder;
   private static Object sfm;

   static {
      try {
         cShellFolder = Class.forName("sun.awt.shell.ShellFolder");
         cShellFolderManager = Class.forName("sun.awt.shell.ShellFolderManager");
         ctrShellFolderManager = cShellFolderManager.getDeclaredConstructor(new Class [] {});
         ctrShellFolderManager.setAccessible(true);
         sfm = ctrShellFolderManager.newInstance(new Object [] {});
         mCreateShellFolder = cShellFolderManager.getDeclaredMethod("createShellFolder",new Class [] {File.class});
         mCreateShellFolder.setAccessible(true);
      } catch(Exception e) {
         e.printStackTrace();
         cShellFolder = cShellFolderManager = null;
         ctrShellFolderManager = null;
         mCreateShellFolder = null;
         sfm = null;
      }
   }

   public static final File attemptReplaceWithShellFolder(File actual) {
      File result = actual;
      if(cShellFolder != null && !cShellFolder.isInstance(actual)) {
         try {
            result = (File) mCreateShellFolder.invoke(sfm, (new Object [] {actual}));
            System.out.print(".");
         } catch(Exception e) {
            System.out.print("#");
         }
      }
      return result;
   }

   public final static class FileSnapshot {
      private static Method mGetBooleanAttributes;
      private static int BA_DIRECTORY, BA_EXISTS, BA_REGULAR, BA_HIDDEN;
      private static Object fs;

      public final boolean isDirectory, exists, isRegular, isHidden;

      public FileSnapshot(File f) {
         boolean e, d, r, h;
         
         try {
            int ba = ((Integer)mGetBooleanAttributes.invoke(fs, new Object [] {f})).intValue();
            d = (ba & BA_DIRECTORY)!=0;
            e = (ba & BA_EXISTS)!=0;
            r = (ba & BA_REGULAR)!=0;
            h = (ba & BA_HIDDEN)!=0;
         } catch(Exception x) {
            d = f.isDirectory();
            e = d || f.exists();
            r = f.isFile();
            h = f.isHidden();
         }
         
         isDirectory = d; exists = e; isRegular = r; isHidden = h;
      }

      static {
         try {
            Class cFile = Class.forName("java.io.File");
            Class cFileSystem = Class.forName("java.io.FileSystem");
            mGetBooleanAttributes = cFileSystem.getDeclaredMethod("getBooleanAttributes", new Class [] {File.class});
            Field fBA_EXISTS = cFileSystem.getDeclaredField("BA_EXISTS");
            Field fBA_REGULAR = cFileSystem.getDeclaredField("BA_REGULAR");
            Field fBA_DIRECTORY = cFileSystem.getDeclaredField("BA_DIRECTORY");
            Field fBA_HIDDEN = cFileSystem.getDeclaredField("BA_HIDDEN");
            Field fFs = cFile.getDeclaredField("fs");

            mGetBooleanAttributes.setAccessible(true);
            fFs.setAccessible(true);
            fBA_EXISTS.setAccessible(true);
            fBA_REGULAR.setAccessible(true);
            fBA_DIRECTORY.setAccessible(true);
            fBA_HIDDEN.setAccessible(true);

            BA_EXISTS = ((Integer)fBA_EXISTS.get(null)).intValue();
            BA_REGULAR = ((Integer)fBA_REGULAR.get(null)).intValue();
            BA_DIRECTORY = ((Integer)fBA_DIRECTORY.get(null)).intValue();
            BA_HIDDEN = ((Integer)fBA_HIDDEN.get(null)).intValue();
            fs = fFs.get(null);
         } catch(Exception e) {}
      }
   }
}
(Incident Review ID: 255591) 
======================================================================

Comments
EVALUATION JSR-203 provides for bulk access to file attributes.
16-02-2009

EVALUATION Perhaps this functionality should be considered for JSR203. Not for Tiger. ###@###.### 2004-04-23
23-04-2004