|
![]() |
名片设计 CorelDRAW Illustrator AuotoCAD Painter 其他软件 Photoshop Fireworks Flash |
|
在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方式中,会要求你控制台输入某个文件对应的目标路径,这是对于新文件(即原来目标目录中没有的文件,新添的),对于对老文件的修改,我们都可以在配置文件中得到目标路径.下面我们看看配置文件如何得到.在这各之前,我们提到几个工具方式: 1.取文件名的扩展名,传入文件名,返回扩展名. /** * * @param fileName * @return */ private String getExt(String fileName){ int pos=fileName.lastIndexOf("."); if(pos>0){ return fileName.substring(pos+1,fileName.length()); } return null; } 2.判定一个目录是否有子目录,传入一个目录,判定有没有子目录,没则有返回true,有子目录返回false /** * 判定一个目录是否有子目录,没有返回true * @param dir * @return */ private boolean hasNoSub(String directory){ File dir=new File(directory); if(!dir.isDirectory()){ //当前不是目录,肯定没有子目录 return true; } String[] subs=dir.list(); for(int i=0;i<subs.length;i++){ //对每个子元素进行判定,有目录就直接返回false File tmp=new File(dir+File.separator+subs[i]); if(tmp.isDirectory()){ return false; } } return true; } 那么我们的配置文件记录什么,什么样的格式?假设我们指定我们的目标路径,类变量objPath=d:/ProjectX/src 那么我们的配置生成象这样: business_1:com.comX.foreg.a.a1 business_2:com.comX.foreg.a.a2 假如a组的另外一个用例a3在business_1文件夹下,则配置文件的第一条配置信息为: business_1:com.comX.foreg.a.a1|com.comX.foreg.a.a3 依次类推,通过文件的包信息与每条配置信息进行匹配,得知它所在的文件夹,当然假如objPath设置为d:/projectX/的话,那么配置信息的:前面部分为src/business_1.就这样,我们得到了可以使用的配置文件.下面我们看看配置文件相关的模块. 1.给定配置文件,把配置信息读入到类变量lines,它的每一个元素就是一条配置信息(配置文件的一行),同时把配置信息中:号前面的部分,我们称之为配置信息头(如business_1或src/business_1),取到我们的类变量heads中,它的作用就是为了提高处理效率,使得我们不用每次都配置信息中取头信息. /** * 读取配置文件,到ArrayList和heads * @return */ private boolean readCfg(File cfgFile){ try{ BufferedReader fr=new BufferedReader(new FileReader(cfgFile)); String line=fr.readLine(); while(line!=null){ //处理当前行 line.trim(); lines.add(line); line=fr.readLine(); } int size=lines.size(); heads=new String[size]; for(int i=0;i<size;i++){ line=(String)lines.get(i); heads[i]=getHead(line); } fr.close(); } catch(IOException ie){ ie.printStackTrace(); return false; } return true; } 2.把一条配置信息的头解析出来,就是上面方式出现的getHead /** * 取得一条配置文件的头 例如business_1: * @param line 一条配置文件 * @return */ private String getHead(String line){ int pos=line.indexOf(":"); if(pos==-1){ ps.println("配置文件有错"); return ""; } return line.substring(0,pos); } 3.该方式的作用就是,把我们的类变量lines的信息写入到配置文件中,因为可能有新添加的文件,用户输入了新的配置信息,或者在交互时,某些配置信息发生了变化. /** * 写入配置文件 * @return */ private boolean saveCfg(File cfgFile){ if(lines==null||lines.size()==0){ return false; } try{ cfgFile.delete(); cfgFile.createNewFile(); BufferedWriter bw=new BufferedWriter(new FileWriter(cfgFile)); int size=lines.size(); for(int i=0;i<size;i++){ bw.write((String)lines.get(i)); bw.newLine(); } bw.flush(); bw.close(); } catch(IOException ie){ ie.printStackTrace(); return false; } return true; } 上面的方式都是我们和配置文件的交互的一个过程,我们下一个问题时,如何初始化生成这个配置文件,基本上有下面几个模块: 1.这就是我们生成配置文件的根本,实际上就是到目标路径中收集结构信息的过程,其中可能调用一些工具方式. /** * 生成配置文件 * @param pac 包路径 * @param path 文件路径 * @return 返回保存是否准确 */ public boolean createCfg(){ File dir=new File(objPath); //到目标路径中去收集信息 String[] dirs=dir.list(); String curDir; char sep=File.separatorChar; String line; for(int i=0;i<dirs.length;i++){ //到每一个子元素(文件或目录)下工作 if(!new File(objPath+sep+dirs[i]).isDirectory()){ //当前元素不是目录,做下一个 continue; } globalLine=null; curDir=objPath+sep+dirs[i]+sep+"src"; getPath(curDir,null); //到当前目录下继承搜寻信息,getPath. line=dirs[i]+":"+globalLine; lines.add(line); } File cfgFile=new File(filePath+sep+configeFile); saveCfg(cfgFile); //保存配置信息 return true; } 其中curDir =...那一行是当前路径,其中的"src"因为我所在项目的子文件下还有一个src目录,但他不是包信息包含的,就像是我们的business_1下面为src/com/comX/...等等,所以就直接加上了. 明眼人一眼就能看出,要害方式是getPath,他是递归的,就像这样: 2.当前子目录下递归收集信息,对于每一条路径,我们只保存最长的,因为短的是可以在长的路径匹配得到的. /** * 递归收集 * @param root 上一级目录 * @param pack 当前已经收集到的信息 */ private void getPath(String root,String pack){ if(hasNoSub(root)){ //假如没有了子目录 if(globalLine==null){ globalLine=pack; } else{ globalLine+="|"+pack; } return; } File dir=new File(root); char sep=File.separatorChar; String[] subs=dir.list(); for(int i=0;i<subs.length;i++){ String curPath=root+sep+subs[i]; File tmp=new File(curPath); if(tmp.isDirectory()){ if(pack==null){ //假如是目录,则递归 getPath(curPath,subs[i]); } else{ getPath(curPath,pack+"."+subs[i]); } } } } 其中用到了类变量globalLine,它最终在调用完成的时候,会返回一条完整的配置信息. 好了,我就讲这么多了,不知道有没有讲明白,希望对你有所帮助,谢谢,最后一个方式是excute方式,就是执行这个完整的分类拷贝文件的工作.我把完整的类放在下面,就不另外写了.(这个类带有我本身项目的痕迹,不过不多,稍改即可) import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; /** * <p>Title: </p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2004</p> * <p>Company: </p> * @author Caoxh * @version 1.0 */ public class SaveFile{ private String filePath="D://Work//upload"; //文件上传路径 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; //记录一条配置信息 /** * 读取一个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; } /** * 取得一条配置文件的头 例如sbzs: * @param line 一条配置文件 * @return */ private String getHead(String line){ int pos=line.indexOf(":"); if(pos==-1){ ps.println("配置文件有错"); return ""; } return line.substring(0,pos); } /** * 读取配置文件,到ArrayList和heads * @return */ private boolean readCfg(File cfgFile){ try{ BufferedReader fr=new BufferedReader(new FileReader(cfgFile)); String line=fr.readLine(); while(line!=null){ //处理当前行 line.trim(); lines.add(line); line=fr.readLine(); } int size=lines.size(); heads=new String[size]; for(int i=0;i<size;i++){ line=(String)lines.get(i); heads[i]=getHead(line); } fr.close(); } catch(IOException ie){ ie.printStackTrace(); return false; } return true; } /** * 写入配置文件 * @return */ private boolean saveCfg(File cfgFile){ if(lines==null||lines.size()==0){ return false; } try{ cfgFile.delete(); cfgFile.createNewFile(); BufferedWriter bw=new BufferedWriter(new FileWriter(cfgFile)); int size=lines.size(); for(int i=0;i<size;i++){ bw.write((String)lines.get(i)); bw.newLine(); } bw.flush(); bw.close(); } catch(IOException ie){ ie.printStackTrace(); return false; } return true; } /** * * 通过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; } /** * 把该文件拷贝到完整的路径中去 * @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; } /** * 生成配置文件 * @param pac 包路径 * @param path 文件路径 * @return 返回保存是否准确 */ public boolean createCfg(){ File dir=new File(objPath); String[] dirs=dir.list(); String curDir; char sep=File.separatorChar; String line; for(int i=0;i<dirs.length;i++){ if(!new File(objPath+sep+dirs[i]).isDirectory()){ continue; } globalLine=null; curDir=objPath+sep+dirs[i]+sep+"src"; getPath(curDir,null); line=dirs[i]+":"+globalLine; lines.add(line); } File cfgFile=new File(filePath+sep+configeFile); saveCfg(cfgFile); return true; } /** * 递归收集 * @param root * @param pack */ private void getPath(String root,String pack){ if(hasNoSub(root)){ //假如没有了子目录 if(globalLine==null){ globalLine=pack; } else{ globalLine+="|"+pack; } return; } File dir=new File(root); char sep=File.separatorChar; String[] subs=dir.list(); for(int i=0;i<subs.length;i++){ String curPath=root+sep+subs[i]; File tmp=new File(curPath); if(tmp.isDirectory()){ if(pack==null){ //假如是目录,则递归 getPath(curPath,subs[i]); } else{ getPath(curPath,pack+"."+subs[i]); } } } } /** * 判定一个目录是否有子目录,没有返回true * @param dir * @return */ private boolean hasNoSub(String directory){ File dir=new File(directory); if(!dir.isDirectory()){ return true; } String[] subs=dir.list(); for(int i=0;i<subs.length;i++){ File tmp=new File(dir+File.separator+subs[i]); if(tmp.isDirectory()){ return false; } } return true; } /** * * @param fileName * @return */ private String getExt(String fileName){ int pos=fileName.lastIndexOf("."); if(pos>0){ return fileName.substring(pos+1,fileName.length()); } return null; } /** * 循环处理一个文件夹 */ public void excute(){ char sep=File.separatorChar; File list=new File(filePath+sep+"list.txt"); File dir=new File(filePath); if(!dir.exists()||!dir.isDirectory()){ //指定的不是目录 ps.println("指定上传文件的目录不准确"); return; } File cfgFile=new File(filePath+sep+configeFile); try{ PrintStream psList=new PrintStream(new FileOutputStream(list)); if(!cfgFile.exists()&&!cfgFile.createNewFile()){ //配置文件不存在 ps.println("指定的配置文件不存在"); return; } if(!readCfg(cfgFile)){ //读入配置文件失败 ps.println("读入配置文件失败"); return; } File[] files=dir.listFiles(); if(files.length<2){ //没有要上传的文件 ps.println("指定的目录中没有文件"); return; } //逐个文件处理 for(int i=0;i<files.length;i++){ File curFile=files[i]; if(!curFile.isFile()||!getExt(curFile.getName()).equals("java")){ continue; } psList.println(curFile.getName()); //当前文件是java文件 String pac=readPac(curFile); //取该文件的包路径 ps.println("读包完成...."); if(pac==null){ // ps.println("文件读出包路径出错"); return; } String path=parsePac(pac,cfgFile); //通过package取路径 ps.println("解析完成...."); if(path==null){ ps.println("取文件的保存路径出错"); continue; //跳过这个文件 } //组装成一个完整的路径 String fullPath=objPath+sep+path+sep+"src"+sep+pac.replace(\\\'.\\\',sep); ps.println("建立拷贝路径:"+fullPath); if(!copy(curFile,fullPath)){ ps.println("拷贝文件失败"+curFile.getName()); continue; } curFile.delete(); ps.println("成功保存一个文件"); } ps.println("成功保存所有文件"); if(!saveCfg(cfgFile)){ ps.println("保存配置文件失败"); return; } } catch(IOException ie){ ie.printStackTrace(); } } /** * 构造函数 */ public SaveFile(){ try{ File log=new File(filePath+File.separator+"cf.log"); if(log.exists()){ log.delete(); } log.createNewFile(); FileOutputStream fos=new FileOutputStream(log); ps=new PrintStream(fos); } catch(IOException ie){ ie.printStackTrace(); System.out.print("创建日志失败!"); ps=System.out; } lines=new ArrayList(); } public static void main(String[] args){ SaveFile sf=new SaveFile(); if(args.length==1){ if(args[0].equals("mc")){ //生成配置文件 sf.createCfg(); } if(args[0].equals("cf")){ //完成分类拷贝工作 sf.excute(); } } else{ sf.ps.println("请指定参数:/n mc 生成配置文件/n cf 拷贝文件"); return; } } } 返回类别: 教程 上一教程: 常用JAVA方式 下一教程: 虚拟机概论(四)??虚拟机的历史 您可以阅读与"Java实现分类文件拷贝"相关的教程: · Java中实现文件拷实例 · DOM文档操作和XML文件互相转变的JAVA实现 · 一个用JAVA实现了文件基本治理的软件 · Javascript 中 浅拷贝与深拷贝的实现 · JavaBean实现多文件上传的两种方式 |
![]() ![]() |
快精灵印艺坊 版权所有 |
首页![]() ![]() ![]() ![]() ![]() ![]() ![]() |