1.对目录和文件递归穷举
/* 列出指定目录下的文件或者文件夹,包含子目录中的内容 也就是列出目录下所有的内容 例如:new File(d:\\);在d盘下还有一个abc目录而abc下还有文件和目录,而用list()方法只能获取到d盘下的文件和目录 */ package filedemo; import java.util.Arrays; import java.io.File;class FileFilterDemo2{/*采用了递归(重复调用使用自身功能),即首先遍历该目录下所有文件/目录一旦遍历到目录,在调用自身进行遍历.*/public static String level(int n){StringBuilder sb=new StringBuilder();sb.append("|-");while((n--)!=0)sb.insert(0," ");//不断的向"|-"前插入空格return sb.toString();}public static void getFiles(File f,int level){System.out.println(level(level)+f);level++;//递归调用为下一级目录File[] dirFiles=f.listFiles();//获取到该目录下所有的文件和目录,其中File对象都采用File(File parent,String child)构造if(dirFiles==null||dirFiles.length==0)//说明传入的pathName不表示目录或目录为空,那么不需要遍历return;elsefor(File file : dirFiles){if(file.isDirectory())//当file中的对象的child依然是目录接着遍历 getFiles(file,level);elseSystem.out.println(level(level)+file);}}public static void main(String[] args){getFiles(new File("f:\\a"),0);} }
关于递归注意事项:
/* 递归注意:一定要有出口(也就是限定条件),不然相当于死循环递归次数过多,会导致OutOfMemoryError(内存溢出) */ class RecursionTest{/*十进制->二进制*/public static void toBin(int num){if(num>0){toBin(num/2);System.out.print(num%2);}}/*求前n项和*/public static int getSum(int n){if(n==1)return 1;elsereturn n+getSum(n-1);}public static void main(String[] args){toBin(10);System.out.println("\n"+getSum(80000));//不断在内存中开辟空间->OutOfMemoryError(内存溢出) } }
2.递归删除指定目录:
/*删除一个带内容的目录删除原理:在windows中,删除目录从目录里面往外删除从里往外删->递归 */ package filedemo; import java.io.File; class RemoveDir{public static void removeDir(File f){File[] allFile=f.listFiles();if(allFile==null||allFile.length==0)//空文件夹/文件 直接删除 System.out.println(f.delete());else{//遍历到最内层->删除,删除完内层->逐步往外删for(File files : allFile){if(files.isFile())System.out.println(files.delete());elseremoveDir(files);}System.out.println(f.delete());//当for执行完,说明该目录下文件已经全部删除,需要删除该目录 }}public static void main(String[] args){removeDir(new File("h:\\a"));} }对于运行结果,(依然是上面遍历的测试目录)会删除9次,会有9个boolean值并且必须都为true,否则可能为同一个文件/目录多次删除
3.File练习:
/*获取到指定目录中所有java文件的路径,并输出到一个文件中. 思想: ①对目录进行递归搜索 ②对于文件只要以.java结尾文件 ③把.java文件路径存入ArrayList集合中.*/ package filedemo; import java.io.File; import java.io.IOException; import java.io.BufferedWriter; import java.io.FileWriter; import java.util.ArrayList; import java.util.List; class JavaFilesList{public static void getJavaFiles(File dir,List<File> list){File[] files=dir.listFiles();if(files!=null && files.length!=0)for(File f : files)if(f.isDirectory())getJavaFiles(f,list);elseif(f.getName().endsWith(".java"))list.add(f);}public static void writeFile(List<File> list,String javaListFile){BufferedWriter bfw=null;File[] javaFiles=list.toArray(new File[list.size()]);//集合转数组try{bfw=new BufferedWriter(new FileWriter(javaListFile));for(File f : javaFiles){bfw.write(f.getAbsolutePath());//获取到绝对路径写入,list存入File对象不一定封装的是绝对路径,可能是相对路径 bfw.newLine();bfw.flush();}bfw.write("一共"+list.size()+"个java文件");}catch(IOException e){throw new RuntimeException("写文件异常");}finally{try{if(bfw!=null)bfw.close();}catch(IOException e){throw new RuntimeException("关闭流异常");}try{Runtime.getRuntime().exec("notepad.exe "+javaListFile);//写完后,自动用记事本打开查看内容 }catch(IOException e){e.printStackTrace();}}}public static void main(String[] args){ List<File> list=new ArrayList<File>();getJavaFiles(new File("g:\\JavaCode"),list);System.out.println(list.size());writeFile(list,"f:\\JavaFiles.txt");//写入文件 } }将制定文件夹从源路径复制到目的路径下:
/* 采用递归方法遍历文件夹中的内容 例如:C:\s\abc->d:\ 将abc文件夹及文件夹的所有文件/文件夹拷贝到d盘下AbsolutePath abc 1.txt ->d:\abcdef ->d:\abc\ def2.txt ->d:\abc\def\ 2.txtghk ->d:\abc\def\ ghk3.txt ->d:\abc\def\ghk\ 3.txtmnl ->d:\abc\mnl */ /* 递归过程:1. src: c:\s\abc dest: d:\dest<-d:\abc 创建abccopyFile(c:\s\abc\1.txt,d:\abc\1.txt)copyDir(c:\s\abc\def,d:\abc) 2.src:c:\s\abc\defdest:d:\abcdest<-d:\abc\def 创建defcopyFile(c:\s\abc\def\2.txt,d:\abc\def\2.txt)copyDir(c:\s\abc\def\ghk,d:\abc\def) 3.... */ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; class CopyDirectory{public static void copyFile(File src,File dest)throws IOException{FileInputStream fis=new FileInputStream(src);FileOutputStream fos=new FileOutputStream(dest);byte[] byteArr=new byte[1024*1024];int bytes=0;while((bytes=fis.read(byteArr))!=-1)fos.write(byteArr,0,bytes);fis.close();fos.close();}public static void copyDir(File src,File dest)throws IOException{File[] files=src.listFiles();dest=new File(dest.getPath()+"\\"+src.getName());//例如:第一次 创建 d:+\+abcdest.mkdir(); // 第二次 创建 d:\abc +\+ deffor(File f : files)if(f.isFile())copyFile(new File(f.getAbsolutePath()),new File(dest.getPath()+"\\"+f.getName()));//例如:当遍历到1.txt时 //C:\s\abc\1.txt,d:\abc\1.txtelse//对于文件夹操作copyDir(new File(f.getAbsolutePath()),dest);//例如:当遍历到def时//C:\s\abc\def,d:\abc } public static void main(String[] args)throws IOException{copyDir(new File("C:\\s\\abc"),new File("d:\\"));//abc文件夹以及文件夹中的内容拷贝到D盘下 System.out.println(new File("d:\\def\\"+"\\"+"\\"+"abc").getPath());System.out.println(new File("d:\\def\\"+"abc")); /*以上两者结果相同(d:\def\abc),也就是说文件系统中会去除多余的\,但是d:\\与d:结果不同,一个为d:\\,一个为d:
*/}}
4.Properties类方法:
/* 在System类中的获取系统属性用到PropertiesProperties 类表示了一个持久的属性集。 Properties 可保存在流中或从流中加载。 属性列表中每个键及其对应值都是一个字符串。 该集合是和IO技术相结合的集合容器 该对象特点:可以用于键值对形式的配置文件(.ini) 在加载数据时,需要数据有固定格式:Key=Value */ package propertydemo; import java.util.Properties; import java.util.Set; import java.io.FileReader; import java.io.FileWriter; import java.io.BufferedReader; import java.io.IOException; class PropertiesDemo{/*自定义方法将文件中的数据存储到Properties集合中该文件中的数据是以键值对形式存在例如:info.txt: zhangsan=18lisi=25...*/public static void storeInProperties()throws IOException{BufferedReader bfr=new BufferedReader(new FileReader("info.txt"));Properties pro=new Properties();String line=null;while((line=bfr.readLine())!=null)if(!line.startsWith("#")){//注释信息不再加入集合String[] keyValue=line.split("=");//以"="分割pro.setProperty(keyValue[0],keyValue[1]); }System.out.println(pro);bfr.close();}/*利用Properties中的load方法完成void load(InputStream inStream) 从输入流中读取属性列表(键和元素对)。 void load(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。*/public static void storeInProperties_2()throws IOException{FileReader fr=new FileReader("info.txt");Properties pro=new Properties();pro.load(fr);System.out.println(pro);pro.list(System.out);// void list(PrintStream out)//将属性列表输出到指定的输出流。/* 此时如果改变了键值对信息,但是改变后的信息依然在内存中,如果想把改变反映到文件中,需要用到store方法*/pro.setProperty("zhangsan","30");System.out.println(pro);FileWriter fw=new FileWriter("info.txt");pro.store(fw,"heihei");//heihei为注释信息//在文件中为#heihei fr.close();fw.close();}/*Properties存储和获取方法*/public static void propertiesMethodDemo(){Properties prop=new Properties();prop.setProperty("zhang","15");//底层在使用HashTable<Object,Object>的put方法prop.put("li","30");System.out.println(prop);Set<String> names=prop.stringPropertyNames();//返回Key的set集合for(String n : names)System.out.println(n+"="+prop.getProperty(n));}public static void main(String[] args)throws IOException{propertiesMethodDemo();System.out.println();storeInProperties();System.out.println();storeInProperties_2();} }
5.Properties的load与store练习:
/* 需求:用于记录应用程序运行次数.如果使用次数已到,那么给出注册提示. 分析:很容易想到的是:计数器可是该计数器 用程序的退出,该计数器也在内存中消失了 下一次在启动该程序,又重新开始从0计数. 这样不是所需要的程序即使结束,该计数器的值也存在 下次程序启动会先加载该计数器的值 并+1后重新存储起来所以需要建立一个配置文件.用于记录软件使用次数该配置文件使用键值对的形式 这样便于阅读数据,并操作数据键值对数据是map集合. 数据是以文件形式存储,使用io技术 那么map+io-->properties配置文件可以实现应用程序数据共享 */ package propertiestest; import java.util.Properties; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.File; class PropertiesTest{/*每次程序运行获取使用次数(counts),并在获取完之后,++counts存入到配置文件中*/public static void checkCounts()throws IOException{ File f=new File("set.ini");Properties pro=new Properties();if(!f.exists())//文件第一次不存在需要创建 f.createNewFile();FileReader fr=new FileReader(f);pro.load(fr);int count=0; String value=pro.getProperty("counts"); if(value!=null)//新建文件中没有counts,此时不再获取,只写count=Integer.parseInt(pro.getProperty("counts"));if(count>=3){//该软件只能够使用三次System.out.println("免费次数已用完");return;//>=3不再写入直接返回 }FileWriter fw=new FileWriter(f); pro.setProperty("counts",(++count)+""); pro.store(fw,"number of use"); fr.close(); fw.close(); /*关于pro.store():所有写入各个项后,刷新输出流(内部在把属性集写入输出流后调用了flush)此方法返回后,输出流仍保持打开状态。 但没有关闭写入流 */}public static void main(String[] args)throws IOException{checkCounts();} } /* 注意:①配置文件不存在,需要创建②需要写入键值对*/
6.PrintStream与PrintWriter
/* 打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印 字节打印流:PrintStreamPrintStream(File file) file-同下PrintStream(String fileName) fileName -要用作此打印流目标的文件名称。如果存在该文件,则将其大小截取为零;否则,创建一个新文件。将输出写入文件中,并对其进行缓冲处理。 PrintStream(OutputStream out) 字符打印流:PrintWriter PrintWriter(File file) PrintWriter(OutputStream out)根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。此便捷构造方法创建必要的中间 OutputStreamWriter,后者使用默认字符编码将字符转换为字节。PrintWriter(String fileName) PrintWriter(Writer out)//比PrintStream多了一个可以接收字符输出流的构造函数 */ package printdemo; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.FileWriter; class PrintStreamDemo{public static void main(String[] args)throws IOException{BufferedReader bufr =new BufferedReader(new InputStreamReader(System.in));//PrintWriter out=new PrintWriter(System.out);//PrintWriter通用性比较强,在写入流后,需要刷新/*
System.out在内部会被封装为new BufferedWriter(new OutputStreamWriter(System.out))
*///PrintWriter out=new PrintWriter(System.out,true);//autoFlush-boolean 变量;如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区,下面由于用到println所以可以不用out.flushPrintWriter out=new PrintWriter(new FileWriter("PrintWriter.txt"),true);//true含义同上,这样写可以把new FileWriter中的数据刷新到文本中,而不用在out.flush String line=null;while((line=bufr.readLine())!=null){out.println(line);//将值打印初始化的流对象中//out.flush();//刷新的是初始化时的流对象 }bufr.close();out.close();} }
7.SequenceInputStream:
/* SequenceInputStream(顺序输入流):表示其他输入流的逻辑串联。它从输入流的有序集合开始, 并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。 该类的由来:例如:已知:四个文件:src1.txt,src2.txt,src3.txt,dest.txt;需求:把前三个文件中数据写入到dest.txt中分析:src1.txt--->FileReader("src.txt")--->FileWriter("dest.txt",true)-->dest.txtsrc2.txt,src3.txt同理 每个源和目的需要单独的IO流对象操作,非常麻烦SequenceInputStream作用:对多个源依次操作,更加方便.*/ package sequenceinputstream; import java.io.*; import java.util.*; class SequenceDemo{public static void main(String[] args)throws IOException{/*SequenceInputStream(Enumeration<? extends InputStream> e) 该构造函数形参为枚举->集合Vector<E>的elements返回Enumeration<E>*/ Vector<FileInputStream> vector=new Vector<FileInputStream>();vector.add(new FileInputStream("f:\\src1.txt"));vector.add(new FileInputStream("f:\\src2.txt"));vector.add(new FileInputStream("f:\\src3.txt"));Enumeration<FileInputStream> en=vector.elements();SequenceInputStream sis=new SequenceInputStream(en);BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("f:\\dest.txt"));//FileOutputStream fis=new FileOutputStream("f:\\dest.txt");int aByte=0;//byte[] b=new byte[1024];while((aByte=sis.read())!=-1){bufos.write(aByte);bufos.flush();}/*int bytes;while((bytes=sis.read(b))!=-1)fis.write(b,0,bytes); }*/bufos.close();sis.close();}}
文件切割和合并综合练习:
/* 切割文件:其实就是一个源(该文件)对应多个目的(多个碎片文件) 切割①需要一个输入流对象关联该文件②为了控制每次读取大小,自定义一个缓冲(数组)③循环读取,每次读取将读取的数据,通过输出流写入一个文件中,直至源文件末尾(-1) 合并多个源对应一个目的,这里可以采用SequenceInputStream */import java.io.FileInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.io.SequenceInputStream; import java.util.Enumeration; import java.util.Iterator; class SplitFileTest{/*当文件不太大时,指定的缓冲区可以为分割的文件大小*/public static void splitFile_1(String file)throws IOException{/*以切割图片为例*/FileInputStream fis=new FileInputStream(file);byte[] b=new byte[1024*1024];//每次最多分割1MBFileOutputStream fos=null;int bytes=0,count=1;while((bytes=fis.read(b))!=-1){fos=new FileOutputStream("f:\\part"+(count++)+".part");//每次新建一个流对象关联一个新的文件 fos.write(b,0,bytes); fos.close();//每次循环关闭上次的流对象 }fis.close();} /*当文件特别大(例如2GB),而需要按400MB分割,不建议定义400MB缓冲区,定义小点缓冲区40MB,使切割文件满足制定大小*/public static File[] splitFile_2(File f)throws IOException{FileInputStream fis=new FileInputStream(f);byte[] byteArr=new byte[1024*1024];ArrayList<File> arrList=new ArrayList<File>();int bytes=0;int count=0;File wf=null;FileOutputStream fos=null;while((bytes=fis.read(byteArr))!=-1){if(wf==null||wf.length()==2*1024*1024){if(fos!=null)fos.close();//关闭与上一个文件相关联的写入流对象wf=new File("C:\\Users\\ZhangHongQ\\Desktop\\java复习\\"+(++count)+".part");arrList.add(wf);fos=new FileOutputStream(wf);}fos.write(byteArr,0,bytes);}fis.close();return arrList.toArray(new File[arrList.size()]);}/*对以上分割的文件进行合并*/public static void mergeFile(File[] file)throws IOException{ArrayList<FileInputStream>al=new ArrayList<FileInputStream>();for(File f : file)al.add(new FileInputStream(f));final Iterator<FileInputStream>it=al.iterator();SequenceInputStream sis=new SequenceInputStream(new Enumeration<FileInputStream>(){public boolean hasMoreElements(){return it.hasNext();}public FileInputStream nextElement(){return it.next();}});FileOutputStream fos=new FileOutputStream(new File("C:\\Users\\ZhangHongQ\\Desktop\\java复习\\Bandari.mp3"));int aByte=0;while((aByte=sis.read())!=-1)fos.write(aByte);sis.close();fos.close();}public static void main(String[] args)throws IOException{File[] file=splitFile_2(new File("F:\\SONG\\Bandari - 爱尔兰风笛.mp3"));//例如:8.93MB的MP3文件System.out.println(Arrays.toString(file));//2MB 2MB 2MB 2MB 934KB mergeFile(file);} }