在Java中对文件进行分类

如果你是个Java程序员,也许你对Java的文件组织已经非常清楚,例如你知道你们项目组是如何把众多的Java文件进行分类,组成整个项目工程.通常你们可能会根据业务来分组.有时候,我们作为项目成员,就会把自己的Java文件根据分组来进行分类的.下面,给出个例子:
某项目ProjectX要给某家名叫comX的商业公司做的信息系统,根据业务需要分为,a,b,c,d四组,采用典型的三层结构,其中,工程中的文件分为前台部分和后台部分.经过分析,该项目最后把文件组织成这样的结构:
a组写的前台文件所在的包为com.comX.foreg.a,相对应的后台文件放在com.comX.backg.a中
b组写的前台文件所在的包为com.comX.foreg.b,相对应的后台文件放在com.comX.backg.b中
c组写的前台文件所在的包为com.comX.foreg.c,相对应的后台文件放在com.comX.backg.c中
d组写的前台文件所在的包为com.comX.foreg.d,相对应的后台文件放在com.comX.backg.d中
当然,这只是我的一种简化的模型,实际上的项目由于业务交叉,综合复杂度等等因素应该比这样的结构复杂的多.象上面这样的工程,最后所有的代码放在文件夹"D:\ProjectX\src\"下面,而下面的文件组织和Java包路径可能又不一样.
现在,我描述一下,我要阐述的问题,当这个工程已经基本完成之后,各个小组都出现了修改,集成发布人员,给项目组开了一个ftp,ftp文件结构正好和原来的结构一样,a组的程序员修改了某个文件后,按照他所在的位置,重新上传.这样,通常会有人把代码传错了位置,最后编译的时候出现错误,对于及其复杂,各组有所交叉的组织来说,编译的时候查错,都很困难.

现在要做的是,让修改后的文件全部都传到一个文件夹中,通过程序把这些文件分发到他们应该在的位置.

好,如何来作?
思路很简单:每个文件都有他们的包路径,既然我们已经有了完整的文件结构,我们就能知道每一个包路径所对应的文件组织中的路径,如有一个文件ClassX.java,我们通过读取他的包路径为com.comX.foreg.a.a1,a1为a组的一个用例,但是它实际所在的位置为:
d:\ProjectX\src\business_1\com\comX\foreg\a\a1\ClassX.java,我们另外一个文件CalssY.java,他的包为com.comX.foreg.a.a2,它是a组的第二个用例,但他的实际存放路径为:d:\ProjectX\src\business_2\com\comX\foreg\a\a2\ClassY.java,
我们就可以根据事先指定的src目录找到他的合适位置.
我所作的是为本项目组的程序员上传文件提供方便,他们把要上传的文件上传到一个文件夹,然后通过这个程序拷贝到正确的位置即可.下面是我实现的一些模块,你可以根据自己的特殊情况来做修改或扩展.

0.处理这个问题需要设置一些类变量:
private String filePath="D:\\Work\\upload"; //文件上传路径,直接指向你的ftp目录吧
private String configeFile="packageConfig.cxh"; //路径配置文件,后面会专门讲到
private String objPath="D:\\Work\\gdlt\\src"; //目标文件路径,你可以指定任意,但要和配置文件一致
private PrintStream ps=null; //输出消息重定向,用于处理过程中的信息输出定向
private ArrayList lines=null; //保存配置文件
String[] heads=null; //保存每条配置的头
String globalLine; //记录一条配置信息

1.传入一个Java文件,返回该Java文件的包路径,如上面的ClassX.java,返回com.comX.foreg.a

/** 

* 读取一个java文件,返回他的package信息取出来 

* @param file 文件句柄 

* @return 返回包路径 

*/ 

private String readPac(File file){ 

String pac=null; 

try{ 

BufferedReader fr=new BufferedReader(new FileReader(file)); //读取器 

String line=fr.readLine(); 

while(line!=null){ //逐行处理 

//处理当前行 

line.trim(); 

if(line.startsWith("package")){ //找到包信息了 

pac=line.substring(7,line.length()-1).trim(); 

break; 

} 

line=fr.readLine(); 

} 

} catch(IOException ie){ 

pac=null; 

ie.printStackTrace(); 

} 

return pac; 

}



2.根据上面返回的包路径,返回该文件应该在的实际位置,例如上面的ClassX.java,返回d:\ProjectX\src\business_2\com\comX\foreg\a\

/** 
* 
* 通过package信息把该文件应该在的位置取出来 
* @param pack 包路径 
* @return 返回该文件应该在的路径 返回null表示识别失败,需要读入 比如sbzs 
* 并智能的更新配置文件 
*/ 
private String parsePac(String pack,File cfgFile){ 
String path=null; 
String line=null; 
try{ 
for(int i=0;i<heads.length;i++){ 
line=(String)lines.get(i); 
if(line.indexOf(pack)>0){ //找到了 
return heads[i]; 
} 
} 
//没有找到,进行询问 
ps.print("请输入包 "+pack+" 所在的路径:(例如:sbzs)"); 
DataInputStream dis=new DataInputStream(System.in); 
path=dis.readLine().trim().toLowerCase(); 
dis.close(); 
if(path==null||path.length()==0){ 
ps.println("没有输入有效的包所在位置"); 
} else{ //得到名字,写入 
int i; 
for(i=0;i<heads.length;i++){ 
if(path.equals(heads[i])){ //找到了目标,把该包加入 
String tmp=(String)lines.get(i)+"|"+pack; 
lines.set(i,tmp); //更新 
break; 
} 
} 
if(i==heads.length){ //目前还没有这个位置,加入并更新 
lines.add(path+":"+pack); 
String[] tmp=new String[heads.length+1]; 
System.arraycopy(heads,0,tmp,0,heads.length); 
tmp[heads.length]=path; 
heads=tmp; 
} 
} 
} catch(IOException ie){ 
path=null; 
ie.printStackTrace(); 
} 
return path; 
}



3.根据上面返回的实际位置,就可以把该文件拷贝到适合的位置.成功返回true

/** 
* 把该文件拷贝到完整的路径中去 
* @param file 文件句柄 
* @param path 文件目标的绝对路径 
* @return 
*/ 
private boolean copy(File file,String fullPath){ 
ps.println("开始拷贝文件...."); 
ps.println("源文件:"+file.getName()); 
ps.println("目标文件在:"+fullPath); 
String fileName=file.getName(); 
int pos=fileName.lastIndexOf(File.separator); 
if(pos>0){ 
fileName=fileName.substring(pos+1,fileName.length()); 
} 
String lastPath=fullPath+File.separator+fileName; 
File objFile=new File(lastPath); 
if(objFile.exists()&&!objFile.delete()){ //如果存在则删除 
ps.println("删除目标文件失败"); 
return false; 
} 
//开始拷贝 
try{ 
objFile.createNewFile(); 
FileInputStream fis=new FileInputStream(file); 
FileOutputStream fos=new FileOutputStream(objFile); 
byte[] buf=new byte[1024]; 
int i=0; 
while((i=fis.read(buf))!=-1){ 
fos.write(buf,0,i); 
} 
fis.close(); 
fos.close(); 
} catch(IOException ie){ 
ie.printStackTrace(); 
return false; 
} 
return true; 
}

到目前为止你可能都已经注意到了,这一切都非常简单,模块的思路也非常清楚.当然你肯定也注意到了,其中最重要的一个角色就是配置文件,如果没有这个,你可以看到在parsePac方法中,会要求你控制台输入某个文件对应的目标路径,这是对于新文件(即原来目标目录中没有的文件,新添的),