利用Java虚拟Unix/Linux的文件路径

  大部分的java程序应用于UNIX/Linux系统,而绝大部分的开发是在Windows下。虽然,java可以运行在anywhere,但毕竟还有很多环境配置问题。
  例如在UNIX下,你需要将某些配置文件的路径写入到另一个配置文件。也许有很多局限,使你必须写入绝对路径。
  在config.properties里写入
  logs=/logs/app/db/logs.properties
  configs=/usr/WebSphere/AppServer/installedApps/appname/earname/warname/WEB-INF/properties/myconfig.properties
  在开发阶段,你是否愿意在你的Windows开发机上建立上面这样的目录,或者逐个修改这个路径呢?尤其在已有的系统下,为了开发新的功能,构筑开发环境时,这种配置文件路径的修改是相当花时间的。并且,在Release时,你必须要使用Ant工具批量修改这些配置文件。但我可以说,大部分项目只有给生产和系统集成测试环境才会配置Ant工具。而在低级别的测试环境下,你只能手动更改。那么如何才能不修改任何文件可以再windows本地调试并运行呢?
  以下,我给出一个小小方案。
  1.重写java.io.File类
  先不要向我丢香蕉皮,重写java.io.File并不一定要变动rt.jar文件。jvm支持pretend,也就是伪装,我可以把我重写的java.io.File在运行期时代替rt.jar原有的java.io.File类。想了解更详细的信息可以在JAVA_HOME里找这个文件:[JAVA_HOME]\bin\client\Xusage.txt
  -Xbootclasspath/p:
  prepend in front of bootstrap class path
  在调试时,我就是要用这个参数。假设,我把重写的java.io.File类文件打包为filemap_1_4.jar。调试时,我就可以运行java-Xbootclasspath/p:D:\MyProject\FileMap/filemap_1_4.jar-cp...
  这样,在我调用的所有类里,涉及到文件或文件系统功能时,都调用D:\MyProject\FileMap/filemap_1_4.jar下面的java.io.File而不是rt.jar.
  2.功能实现
  2.1文件目录映射关系
  为了增加一些灵活性,我使用一个目录映射文件,来定义UNIX/LINUX文件路径和Windows文件路径的映射关系。
  例如,filemap.properties
  /usr/WebSphere/AppServer/installedApps/appname/earname/warname/=C:/MyProject/
  /logs/app/db/=c:/MyProject/logs
  当程序要读取
  /usr/WebSphere/AppServer/installedApps/appname/earname/warname/WEB-INF/properties/myconfig.properties
  文件时,java.io.File会映射到C:/MyProject/WEB-INF/properties/myconfig.properties。
  2.2 java.io.File更改
  增加一个静态变量private static HashMap filemaps=null;用来保存映射关系。
  增加一个私有方法initmaps初始化filemaps
  /**
  *read filemap.propreties to initialize file map.
  */
  private void initmaps(){
  if(filemaps==null){
  filemaps=new HashMap();
  String filemap=System.getProperty("filemap");
  //获得filemap.properties文件路径,需要在jvm运行时传入-Dfilemap=[filemap.properties全路径名],
  不要试图使用classloader.getResource(),因为getResource里也会使用java.io.File,会产生jvm异常。
  if(filemap==null||filemap=="")
  return;
  this.path=fs.normalize(filemap);
  //准备读取filemap.properties文件。因为使用FileInputStream时,
  需要传入一个java.io.File对象,在这暂时把this.path设为filemap.properties的路径。
  this.prefixLength=fs.prefixLength(this.path);
  Properties pro=new Properties();
  try{
  pro.load(new FileInputStream(this));//读取filemap.properties.
  Enumeration enumeration=pro.propertyNames();
  while(enumeration.hasMoreElements()){
  String sourcepath=(String)enumeration.nextElement();
  String targetpath=pro.getProperty(sourcepath);
  filemaps.put(sourcepath,targetpath);//保存到filemaps静态对象里。
  }
  }catch(FileNotFoundException e1){
  return;
  }catch(IOException e2){
  return;
  }
  }
  我们还需要一个私有方法转换路径。
  /**
  *Get Virutal Path string
  * param name原UNIX/Linux路径。
  * return新windows路径。
  */
  private String getVirtualPath(String name){
  Iterator sources=filemaps.keySet().iterator();
  while(sources.hasNext()){
  String source=(String)sources.next();
  if(name.startsWith(source)==true){
  //当原路径包含filemaps里某一个source路径时,将原路径转换为新的target路径。
  String target=(String)filemaps.get(source);
  name=target+name.substring(source.length());
  }
  }
  return name;
  }
  好了,现在准备在java.io.File里调用这两个方法。
  /**
  *Creates a new File instance by converting the given
  *pathname string into an abstract pathname.If the given string is
  *the empty string,then the result is the empty abstract pathname.
  *
  * param pathname A pathname string
  * throws NullPointerException
  *If the pathname argument is null
  */
  public File(String pathname){
  //new function
  initmaps();
  if(pathname==null){
  throw new NullPointerException();
  }
  //new function
  pathname=getVirtualPath(pathname);
  this.path=fs.normalize(pathname);
  this.prefixLength=fs.prefixLength(this.path);
  }
  public File(String parent,String child){
  //new function
  initmaps();
  if(child==null){
  throw new NullPointerException();
  }
  //new function
  child=getVirtualPath(child);
  parent=getVirtualPath(parent);
  if(parent!=null){
  if(parent.equals("")){
  this.path=fs.resolve(fs.getDefaultParent(),
  fs.normalize(child));
  }else{
  this.path=fs.resolve(fs.normalize(parent),
  fs.normalize(child));
  }
  }else{
  this.path=fs.normalize(child);
  }
  this.prefixLength=fs.prefixLength(this.path);
  }
  public File(File parent,String child){
  //new function
  initmaps();
  child=getVirtualPath(child);
  if(child==null){
  throw new NullPointerException();
  }
  if(parent!=null){
  if(parent.path.equals("")){
  this.path=fs.resolve(fs.getDefaultParent(),
  fs.normalize(child));
  }else{
  String parentpath=getVirtualPath(parent.path);
  this.path=fs.resolve(parent.path,
  fs.normalize(child));
  }
  }else{
  this.path=fs.normalize(child);
  }
  this.prefixLength=fs.prefixLength(this.path);
  }
  2.3打包
  将java.io.File编译并打包成jar文件。filemap_1_4.jar
  2.4设置调试环境。
  在你需要调试环境里不需要把这个jar文件发入classpath,但需要在VM arguments里加上
  -Xbootclasspath/p:C:\MyProject\filemap_1_4.jar-Dfilemap=C:\MyProject\filemap.properties
  3.测试
  编写测试程序
  import java.io.BufferedReader;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileReader;
  public class Test{
  /**
  * param args
  */
  public static void main(String[]args){
  FileReader filereader;
  try{
  //打印/usr/WebSphere/AppServer/InstallApp/Test.java
  filereader=new FileReader(
  "/usr/WebSphere/AppServer/InstallApp/Test.java");
  BufferedReader bufferedreader=new BufferedReader(filereader);
  String line=null;
  while((line=bufferedreader.readLine())!=null)
  System.out.println(line);
  //遍历/usr/WebSphere/AppServer/InstallApp/Test.java所在的目录下所有文件,并打印文件名。
  File fl=new File("/usr/WebSphere/AppServer/InstallApp/Test.java");
  String path=fl.getParent();
  String[]files=new File(path).list();
  for(int i=0;i System.out.println(files);
  }
  }catch(Exception e){
  e.printStackTrace();
  }
  }
  }