xscn

博客园 首页 新随笔 联系 订阅 管理

 

框架图

IO(Input Output)流
IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,用于操作流的对象都在IO包中。

流按操作数据分为两种:字节流与字符流 。
流按流向分为:输入流,输出流。

字节流的抽象基类:
•InputStream ,OutputStream。

字符流的抽象基类:
•Reader ,Writer。

注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
•如:InputStream的子类FileInputStream。
•如:Reader的子类FileReader。 

字符流

类 Writer-用于写入字符流的抽象基类。

类 Reader-用于读取字符流的抽象基类。

 1 import java.io.*;
 2 class  FileWriterDemo
 3 {
 4     public static void main(String[] args)
 5     {
 6         FileWriter fw = null; //创建流对象的引用
 7         try{
 8          fw = new FileWriter("Test.txt");//引用指向一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。明确数据要存放的目的地。
 9                                          //该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
10          
11          //fw = new FileWriter("demo.txt",true);////传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。
12          fw.write("hello\r\njava"); //调用write方法,将字符串写入到流中。
13          }
14         catch (IOException e){
15         System.out.println(e.toString());
16          }
17         finally{
18         if(fw!=null)//如果创建流对象出现异常,未能创建流对象,需要判断后才能调用关闭流对象的方法。
19         try{
20         fw.close();//close和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
21         }
22         catch (IOException e){
23         System.out.println(e.toString());
24         }
25         }     
26     }          
27 }

 

 1 import java.io.*;
 2 class  FileReaderDemo
 3 {
 4 public static void main(String[] args)
 5   {
 6      FileReader fr = null;//创建流对象的引用
 7      try{
 8      fr = new FileReader("FileWriterDemo.java"); //引用指向一个FileReader对象,并和指定名称的文件相关联。
 9                                                  //要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException。
10      //定义一个字符数组。用于存储读到字符。
11      char[] buf = new char[1024];
12      int len= 0;
13      while((len=fr.read(buf))!=-1){//该read(char[])返回的是读到字符个数。
14      System.out.print(new String(buf,0,len));
15      }
16      }
17      catch (IOException e){
18      System.out.println("read-Exception :"+e.toString());
19      }
20      finally{
21      if(fr!=null){                                   
22      try{
23      fr.close();
24      }
25      catch (IOException e){
26      System.out.println("close-Exception :"+e.toString());
27      }
28      }
29      }     
30   }
31 } 

练习:将C盘一个文本文件复制到D盘。

 1 /*
 2 复制的原理:
 3 其实就是将C盘下的文件数据存储到D盘的一个文件中。
 4 
 5 步骤:
 6 1,在D盘创建一个文件。用于存储C盘文件中的数据。
 7 2,定义读取流和C盘文件关联。
 8 3,通过不断的读写完成数据存储。
 9 4,关闭资源。
10 */
11 import java.io.*;
12 
13 class CopyText 
14 {
15     public static void main(String[] args)16     {
17         copy();
18     }
19     public static void copy()
20     {
21         FileReader fr = null;
22         FileWriter fw = null;
23         
24         try
25         {
26             fr = new FileReader("C:\\Users\\lenovo\\Desktop\\新建文本文档.txt");
27             fw = new FileWriter("D:\\新建文本文档_copy.txt");
28             
29 
30             char[] buf = new char[1024];
31 
32             int len = 0;
33             while((len=fr.read(buf))!=-1)
34             {
35                 fw.write(buf,0,len);
36             }
37         }
38         catch (IOException e)
39         {
40             throw new RuntimeException("读写失败");
41 
42         }
43         finally
44         {
45             if(fr!=null)
46                 try
47                 {
48                     fr.close();
49                 }
50                 catch (IOException e)
51                 {
52                  System.out.println("读取流关闭异常:"+e.toString());
53                 }
54             if(fw!=null)
55                 try
56                 {
57                     fw.close();
58                 }
59                 catch (IOException e)
60                 {
61                  System.out.println("写入流关闭异常:"+e.toString());
62                 }
63         }
64     }
65 
66 }

字符流的缓冲区 

缓冲区的出现提高了对数据的读写效率。
对应类
•BufferedWriter
•BufferedReader
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强。 

字符写入流缓冲区BufferedWriter

 1 /*
 2 字符写入流缓冲区: 
3
缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。 4 该缓冲区中提供了一个跨平台的换行符。 5 newLine(); 6 写入一个行分隔符。行分隔符字符串由系统属性line.separator定义,并且不一定是单个新行 ('\n') 符。 7 */ 8 import java.io.*; 9 class BufferedWriterDemo 10 { 11 public static void main(String[] args) throws IOException 12 { 13 //创建一个字符写入流对象。 14 FileWriter fw = new FileWriter("Buffer.txt"); 15 16 //为了提高字符写入流效率。加入了缓冲技术。 17 //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。 18 BufferedWriter bufw = new BufferedWriter(fw); 19 20 for(int x=1; x<=5; x++) 21 { 22 bufw.write("abcd"+x); 23 bufw.newLine(); 24 bufw.flush();//记住,只要用到缓冲区,就要记得刷新。 25 } 26 //关闭缓冲区,就是在关闭缓冲区中的流对象。 27 bufw.close(); 28 } 29 }

字符读取流缓冲区BufferedReader

 1 /*
 2 字符读取流缓冲区:
 3 该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
 4 当返回null时,表示读到文件末尾。
 5 
 6 readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
 7 */
 8 import java.io.*;
 9 class  BufferedReaderDemo
10 {
11     public static void main(String[] args) throws IOException
12     {
13         //创建一个读取流对象和文件相关联。
14         FileReader fr = new FileReader("Buffer.txt");
15 
16         //为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
17         BufferedReader bufr = new BufferedReader(fr);
18         
19         String line = null;
20 
21         while((line=bufr.readLine())!=null)
22         {
23             System.out.println(line);
24         }
25         bufr.close();
26     }
27 }

BufferedReader的已知直接子类LineNumberReader

跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int)getLineNumber(),它们可分别用于设置和获取当前行号。

 1 import java.io.*;
 2 class LineNumberReaderDemo 
 3 {
 4     public static void main(String[] args)throws IOException 
 5     {
 6         FileReader fr = new FileReader("Buffer.txt");
 7 
 8         LineNumberReader lnr = new LineNumberReader(fr);
 9 
10         String line = null;
11         //lnr.setLineNumber(100);//设置行号起始,初始值为0行
12         while((line=lnr.readLine())!=null)
13         {
14             System.out.println(lnr.getLineNumber()+":"+line);
15         }
16         lnr.close();
17     }
18 }

装饰设计模式被大量应用在java的IO体系中,例如

Reader    -------相当于Component

  丨--InputStreamReader --------相当于ConcreteComponent

  丨--BufferedReader  -------装饰增强InputStreamReader,特有readLine()功能,相当于Decorator

              丨--LineNumberReader --------BufferedReader的子类,在BufferedReader的基础上,增加跟踪行号的功能,相当于ConcreteDecorator

自定义装饰类MyBufferedReader和MyLineNumberReader

 1 import java.io.*;
 2 class MyBufferedReader extends Reader
 3 {
 4     private Reader r;
 5     MyBufferedReader(Reader r) //多态原理接受需要增强的类
 6     {
 7         this.r = r;
 8     }
 9     //可以一次读一行数据的方法。
10     public String myReadLine()throws IOException
11     {
12         //定义一个临时容器。原BufferReader封装的是字符数组。
13         //为了演示方便。定义一个StringBuilder容器。因为最终还是要将数据变成字符串。
14         StringBuilder sb = new StringBuilder();
15         int ch = 0;
16         while((ch=r.read())!=-1)
17         {
18             //判断回车换行标记
19             if(ch=='\r')
20                 continue;
21             if(ch=='\n')
22                 return sb.toString();
23             else
24                 sb.append((char)ch);
25         }
26         if(sb.length()!=0)//如果容器中有数据就打印出来
27             return sb.toString();
28         return null;        
29     }
30     //覆盖Reader类中的抽象方法。
31     public int read(char[] cbuf, int off, int len) throws IOException
32     {
33         return r.read(cbuf,off,len) ;
34     }
35     public void close()throws IOException
36     {
37         r.close();
38     }
39     public void myClose()throws IOException
40     {
41         r.close();
42     }
43 }
44 class  MyBufferedReaderDemo
45 {
46     public static void main(String[] args) throws IOException
47     {
48         FileReader fr = new FileReader("Buffer.txt");
49         MyBufferedReader myBuf = new MyBufferedReader(fr);
50 
51         String line = null;
52 
53         while((line=myBuf.myReadLine())!=null)
54         {
55             System.out.println(line);
56         }
57         myBuf.myClose();
58     }
59 }
 1 import java.io.*;
 2 class MyLineNumberReader extends MyBufferedReader
 3 {
 4     private int lineNumber;
 5     MyLineNumberReader(Reader r)
 6     {
 7         super(r);
 8     }
 9     public String myReadLine()throws IOException
10     {
11 
12         lineNumber++;
13         return super.myReadLine();
14     }
15     public void setLineNumber(int lineNumber)
16     {
17         this.lineNumber = lineNumber;
18     }
19     public int getLineNumber()
20     {
21         return lineNumber;
22     }
23 }
24 class  MyLineNumberReaderDemo
25 {
26     public static void main(String[] args) throws IOException
27     {
28         FileReader fr = new FileReader("Buffer.txt");
29                     
30         MyLineNumberReader mylnr = new MyLineNumberReader(fr);
31 
32         String line = null;
33         mylnr.setLineNumber(100);
34         while((line=mylnr.myReadLine())!=null)
35         {
36             System.out.println(mylnr.getLineNumber()+"::"+line);
37         }
38         mylnr.myClose();
39     }
40 }

 

字节流

类 OutputStream  此抽象类是表示输出字节流的所有类的超类。

类 InputStream    此抽象类是表示字节输入流的所有类的超类。

 1 import java.io.*;
 2 class  FileStream
 3 {
 4     public static void main(String[] args) throws IOException
 5     {
 6         writeFile();
 7         readFile_1();    
 8     }
 9     public static void readFile_2() throws IOException
10     {
11         FileInputStream fis = new FileInputStream("fos.txt");
12         //定义一个刚刚好的缓冲区。不用在循环了。
13         byte[] buf = new byte[fis.available()];
14         fis.read(buf);
15         System.out.println(new String(buf));
16         fis.close();
17     }
18     public static void readFile_1()throws IOException
19     {
20         FileInputStream fis = new FileInputStream("fos.txt");
21         byte[] buf = new byte[1024];
22         int len = 0;
23         while((len=fis.read(buf))!=-1)
24         {
25             System.out.println(new String(buf,0,len));
26         }
27         fis.close();        
28     }
29     public static void writeFile() throws IOException
30     {
31         FileOutputStream fos = new FileOutputStream("fos.txt");        
32         fos.write("abcde".getBytes());//字符串变字节数组。
33         fos.close();        
34     }
35 }

 

字节流的缓冲区 

缓冲区的出现提高了对数据的读写效率。
对应类
•BufferedInputStream
•BufferedOutputStream

利用缓冲区复制图片,mp3等文件

 1 //利用字节流缓冲区复制图片,mp3等文件
 2 import java.io.*;
 3 class  CopyMP3
 4 {
 5     public static void main(String[] args) 
 6     {
 7          long start = System.currentTimeMillis();
 8          copyMp3();
 9          long end   = System.currentTimeMillis();
10          System.out.println("Copy用时:"+(end-start)+"毫秒");
11     }
12         public static void copyMp3(){
13         
14         BufferedInputStream  bufis =null;
15         BufferedOutputStream bufos =null;
16         try
17         {
18             bufis = new BufferedInputStream(new FileInputStream("0.mp3"));
19             bufos = new BufferedOutputStream(new FileOutputStream("1.mp3"));
20 
21             byte[] buf = new byte[1024];
22 
23             int len = 0;
24 
25             while((len=bufis.read(buf))!=-1)
26             {
27                 bufos.write(buf,0,len);
28             }
29         }
30         catch (IOException e)
31         {
32             throw new RuntimeException("复制文件失败");
33         }
34         finally
35         {
36             try
37             {
38                 if(bufis!=null)
39                     bufis.close();
40             }
41             catch (IOException e)
42             {
43                 throw new RuntimeException("读取关闭失败");
44             }
45             try
46             {
47                 if(bufos!=null)
48                     bufos.close();
49             }
50             catch (IOException e)
51             {
52                 throw new RuntimeException("写入关闭失败");
53             }
54         }
55      }
56 }

System类对IO的支持

static PrintStream err
“标准”错误输出流。一般是键盘。
static InputStream in
“标准”输入流。
static PrintStream out
“标准”输出流。一般是显示器。

改变标准输入输出设备

通过System中的setIn()和setOut()改变设备,例如,将键盘录入改成文 件,System.setIn(new FileInputStream("buf.txt"));;将输出目的改为文件,System.setOut(new PrintStream("buf.txt"));。如果源和目的都改成文件,就是复制。

转换流

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。

为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。使用BufferedReader中的特有方法readLine()例如:

 BufferedReader in
   = new BufferedReader(new InputStreamReader(System.in));

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。

为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。使用BufferedWriter的特有方法newLine()例如:

 BufferedWriter out
   = new BufferedWriter(new OutputStreamWriter(System.out));

平时的读写使用默认的字符编码表,即系统的编码,GBK。转换流可以指定编码表,这也是转换流存在的重要原因,不仅仅是调用readLine()和newLine()。也就是说,只要是涉及到字符编码转换,就需要使用转换流。

 1 /*
 2 通过键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
 3 能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
 4 readLine方法是字符流BufferedReader类中的方法。而键盘录入的read方法是字节流InputStream的方法。
 5 
 6 使用转换流InputStreamReader(字节流转字符流)接收字节流System.in,并使用BufferedReader装饰InputStreamReader,调用readLine方法。
 7 同理
 8 使用转换流OutputStreamWriter(字符流转字节流)接收字节流System.out,并使用BufferedWriter装饰OutputStreamWriter,调用newLine方法。
 9 */
10 import java.io.*;
11 class  TransStreamDemo
12 {
13     public static void main(String[] args) throws IOException
14     {
15 
16         //键盘录入的最常见写法。
17         BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
18 
19         BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
20 
21         String line = null;
22 
23         while((line=bufr.readLine())!=null)
24         {
25             if("over".equals(line))
26                 break;
27             bufw.write(line.toUpperCase());
28             bufw.newLine();
29             bufw.flush();
30         }
31         bufr.close();
32 
33     }
34 }

 

流操作的基本规律:通过三个明确来完成。

1,明确源和目的。
    源:输入流。InputStream  Reader
    目的:输出流。OutputStream  Writer。

2,操作的数据是否是纯文本。
    是:字符流。Reader  Writer
    否:字节流。InputStream  OutputStream

3,当体系明确后,在明确要使用哪个具体的对象。
    通过设备来进行区分:
    源设备:内存,硬盘。键盘
    目的设备:内存,硬盘,控制台。

    是否需要提高效率:是:加入缓冲区(推荐加入);否:不加缓冲区。

 

File类

流操作的只有数据,数据最明显的体现是文件,文件有很多的属性和行为,例如,大小、类型和扩展名,数量也比较多,所以可以抽象描述成类,然后封装成对象。从而方便对文件或文件夹的属性信息进行操作。
File类对象≠硬盘上的文件。
File类是Object类的子类,属于IO体系。File对象可以作为参数传递给流的构造函数。也可以直接将文件实体作为参数传递给流,但是如果使用File对象,可以操作文件实体。

创建File对象

构造方法摘要
File(File parent, String child)
根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
File(String pathname)
通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
File(String parent, String child)
根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File(URI uri)
通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例。

File f1 = new File("d:\\java\\day01\\a.txt");。
File f2 = new File("d:\\java\\day01","b.txt");将目录和文件分成2独立参数,单个参数可以是变量或表达式,例如,(“c:\\”,str)
也可以将目录封装成对象,再作为参数传递。例如,File d = new File("d:\\java\\day01"); File f3 = new File(d,"c.txt");
可以直接打印File对象,打印的是构造函数中的内容,即路径和文件名。

\\目录分割符只适合windows系统,应该使用跨平台分隔符seperator完成分割,例如,new File("d:"+File.separator+"java"+File.separator+"day01");

File类常见方法

1,创建。
    boolean createNewFile():当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。                                
    boolean mkdir():创建文件夹。创建此抽象路径名指定的目录。
    boolean mkdirs():创建多级文件夹。创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。

2,删除。
    boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。
    void deleteOnExit();在程序退出时删除指定文件。

3,判断。
    boolean exists() :测试此抽象路径名表示的文件或目录是否存在。
    

    isFile():测试此抽象路径名表示的文件是否是一个标准文件。----------------必须先判断是否存在。下同。
    isDirectory();测试此抽象路径名表示的文件是否是一个目录。
    isHidden();测试此抽象路径名指定的文件是否是一个隐藏文件。
    isAbsolute();测试此抽象路径名是否为绝对路径名。

4,获取信息。
    getName():
    getPath():
    getParent():
    getAbsolutePath()
    long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。
    long length() 返回由此抽象路径名表示的文件的长度。

操作文件列表

String[] list()
返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
String[] list(FilenameFilter filter)
返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
File[] listFiles()
返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
File[] listFiles(FileFilter filter)
返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
File[] listFiles(FilenameFilter filter)
返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
static File[] listRoots()
列出可用的文件系统根。
  1 import java.io.*;
  2 class  FileDemo
  3 {
  4     public static void main(String[] args) 
  5     {     
  6          listRootsDemo();
  7          System.out.println("------------------------------------");
  8          listDemo();
  9          System.out.println("------------------------------------");
 10          fileNameFilterDemo();
 11          System.out.println("------------------------------------");
 12          listFilesDemo();
 13         
 14     }
 15     //File[] listFiles(),功能类似于list(),都是对路径进行操作,不同的是返回的是对象,可以对其进行操作。开发中使用更广。
 16     public static void listFilesDemo()
 17     {
 18         File dir = new File("D:\\jdk1.7.0");
 19         File[] files = dir.listFiles();
 20         System.out.println(dir.getAbsolutePath()+"目录下的文件列表以及文件大小:");
 21         for(File f : files)
 22         {
 23             System.out.println(f.getName()+"::"+f.length());
 24         }
 25     }
 26     public static void fileNameFilterDemo()
 27     {
 28         File dir = new File("D:\\jdk1.7.0");
 29         //传入参数为过滤器FilenameFilter子类的对象,由于过滤器接口只有一个accept()方法,可以使用匿名内部类。
 30         String[] arr = dir.list(new FilenameFilter()
 31         {
 32             public boolean accept(File dir,String name)//list依照accept()的返回值来判定是否需要将文件放入数组。
 33             {
 34                 return name.endsWith(".html");
 35 
 36             }
 37         });
 38         System.out.println("html文件有:"+arr.length);
 39         for(String name : arr)
 40         {
 41             System.out.println(name);
 42         }
 43     }
 44     public static void listDemo()
 45     {
 46         //调用list方法的file对象必须是封装了一个目录。该目录还必须存在。
 47         File f = new File("D:\\jdk1.7.0");
 48         String[] names = f.list();
 49         System.out.println(f.getAbsolutePath()+"目录下的文件列表:"); 
 50         for(String name : names)
 51         {
 52             System.out.println(name);
 53         }
 54     }
 55     public static void listRootsDemo(){//列出系统所有有效盘符
 56         File[] files = File.listRoots();
 57         System.out.println("列出系统所有有效盘符:");
 58         for(File f : files)
 59         {        
 60             System.out.println(f);
 61         }
 62     }
 63 }
 64 ---------- java ----------
 65 列出系统所有有效盘符:
 66 C:\
 67 D:\
 68 E:\
 69 F:\
 70 G:\
 71 H:\
 72 ------------------------------------
 73 D:\jdk1.7.0目录下的文件列表:
 74 bin
 75 COPYRIGHT
 76 db
 77 include
 78 jre
 79 lib
 80 LICENSE
 81 README.html
 82 register.html
 83 register_ja.html
 84 register_zh_CN.html
 85 release
 86 src.zip
 87 THIRDPARTYLICENSEREADME-JAVAFX.txt
 88 THIRDPARTYLICENSEREADME.txt
 89 ------------------------------------
 90 html文件有:4
 91 README.html
 92 register.html
 93 register_ja.html
 94 register_zh_CN.html
 95 ------------------------------------
 96 D:\jdk1.7.0目录下的文件列表以及文件大小:
 97 bin::12288
 98 COPYRIGHT::3409
 99 db::4096
100 include::4096
101 jre::4096
102 lib::4096
103 LICENSE::41
104 README.html::123
105 register.html::5451
106 register_ja.html::5734
107 register_zh_CN.html::5041
108 release::450
109 src.zip::20718845
110 THIRDPARTYLICENSEREADME-JAVAFX.txt::125105
111 THIRDPARTYLICENSEREADME.txt::175640
112 
113 输出完成 (耗时 0 秒) - 正常终止

列出指定目录下文件或者文件夹,包含子目录中的内容。采用递归的方法,也就是函数自身调用自身。

 1 import java.io.*;
 2 class FileDemo3 
 3 {
 4     public static void main(String[] args) 
 5     {
 6         File dir = new File("D:\\KuGou");
 7         showDir(dir,0);        
 8     }
 9     public static String getLevel(int level)
10     {
11         StringBuilder sb = new StringBuilder();
12         sb.append("|--");
13         for(int x=0; x<level; x++)
14         {        
15             sb.insert(0,"|  ");
16         }
17         return sb.toString();
18     }
19     public static void showDir(File dir,int level)
20     {
21         System.out.println(getLevel(level)+dir.getName());
22         level++;
23         File[] files = dir.listFiles();
24         for(int x=0; x<files.length; x++)
25         {
26             if(files[x].isDirectory())
27                 showDir(files[x],level);
28             else
29                 System.out.println(getLevel(level)+files[x]);
30         }
31     }    
32 }
33 ---------- java ----------
34 |--KuGou
35 |  |--D:\KuGou\0.mp3
36 |  |--Listen
37 |  |  |--D:\KuGou\Listen\Adam Lambert - Trespassing.mp3
38 |  |  |--D:\KuGou\Listen\David Archuleta - Crush.mp3
39 |  |  |--D:\KuGou\Listen\Deemah - Should Have Kissed You.mp3
40 |  |  |--D:\KuGou\Listen\GILLE - やさしくなりたい (English Ver.).mp3
41 |  |  |--D:\KuGou\Listen\Jennifer Lopez - Jenny From The Block.mp3
42 |  |  |--D:\KuGou\Listen\Justin Bieber – Turn To You.mp3
43 |  |  |--D:\KuGou\Listen\Psy - 江南style.mp3
44 |  |  |--D:\KuGou\Listen\Se7en - Red Handed Mp3.mp3
45 |  |  |--D:\KuGou\Listen\潘玮柏 - 转机.mp3
46 |  |  |--D:\KuGou\Listen\陈奕迅 - 浮夸.mp3
47 |  |  |--D:\KuGou\Listen\陈奕迅 - 谢谢侬.mp3
48 |  |--Temp
49 
50 输出完成 (耗时 0 秒) - 正常终止

递归删除有内容的目录。

 1 import java.io.*;
 2 class  RemoveDir
 3 {
 4     public static void main(String[] args) 
 5     {
 6         
 7         File dir = new File("E:\\删除专用文件夹");
 8         removeDir(dir);
 9     }
10     public static void removeDir(File dir)
11     {
12         File[] files = dir.listFiles();
13         
14         for(int x=0; x<files.length; x++)
15         {
16             if(files[x].isDirectory())
17                 removeDir(files[x]);
18             else
19                 System.out.println(files[x].toString()+":-file-:"+files[x].delete());
20         }
21 
22         System.out.println(dir+"::dir::"+dir.delete());
23     }
24 }
25 ---------- java ----------
26 E:\删除专用文件夹\新建文件夹\aaa\bbbb\ccccc::dir::true
27 E:\删除专用文件夹\新建文件夹\aaa\bbbb::dir::true
28 E:\删除专用文件夹\新建文件夹\aaa::dir::true
29 E:\删除专用文件夹\新建文件夹\aaa.txt:-file-:true
30 E:\删除专用文件夹\新建文件夹::dir::true
31 E:\删除专用文件夹::dir::true
32 
33 输出完成 (耗时 0 秒) - 正常终止

打印流PrintStream

打印流相当于对输出流进行了装饰设计,提供了打印方法,方便地可以将各种数据类型的数据都原样打印。

字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream

字符打印流:
PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer。

 1 import java.io.*;
 2 class  PrintStreamDemo
 3 {
 4     public static void main(String[] args) throws IOException
 5     {
 6         BufferedReader bufr = 
 7             new BufferedReader(new InputStreamReader(System.in));
 8 
 9         PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);
10         //参数:
11         // out - 输出流
12         //autoFlush - boolean 变量;如果为 true,则println、printf或format方法将刷新输出缓冲区
13 
14         String line = null;
15 
16         while((line=bufr.readLine())!=null)
17         {
18             if("over".equals(line))
19                 break;
20             out.println(line.toUpperCase());
21         }
22         out.close();
23         bufr.close();
24     }    
25 }

 

合并流SequenceInputStream

SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

SequenceInputStream(Enumeration<? extends InputStream> e)
通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。

 

 1 import java.io.*;
 2 import java.util.*;
 3 class SequenceDemo 
 4 {
 5     public static void main(String[] args) throws IOException
 6     {   
 7         splitFile();
 8         /*1.效率低         
 9         // Vector中添加源  
10         Vector<FileInputStream> v = new Vector<FileInputStream>();
11         v.add(new FileInputStream("1.txt"));
12         v.add(new FileInputStream("2.txt"));
13         v.add(new FileInputStream("3.txt"));
14         // Enumeration<E> elements() 返回此向量的组件的枚举。
15         Enumeration<FileInputStream> en = v.elements();
16         */
17         
18         //2.效率高
19         ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
20 
21         for(int x=1; x<=2; x++)
22         {
23             al.add(new FileInputStream(x+".part"));
24         }
25         // 匿名内部类调用局部变量final修饰
26         final Iterator<FileInputStream> it = al.iterator();
27         // 用匿名内部类的形式实现枚举,内部用迭代器的方法覆盖Enumeration的方法 
28         Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
29         {
30             public boolean hasMoreElements()
31             {
32                 return it.hasNext();
33             }
34             public FileInputStream nextElement()
35             {
36                 return it.next();
37             }
38         };
39         // 合并流            
40         SequenceInputStream sis = new SequenceInputStream(en);
41         // 目的
42         FileOutputStream fos = new FileOutputStream("2.mp3");
43 
44         byte[] buf = new byte[1024];
45 
46         int len =0;
47         while((len=sis.read(buf))!=-1)
48         {
49             fos.write(buf,0,len);
50         }
51         fos.close();
52         sis.close();
53     }
54     //切割
55     public static void splitFile()throws IOException
56     {
57         FileInputStream fis =  new FileInputStream("1.mp3");
58 
59         FileOutputStream fos = null;
60 
61         byte[] buf = new byte[1024*1024];
62 
63         int len = 0;
64         int count = 1;
65         while((len=fis.read(buf))!=-1)
66         {
67             fos = new FileOutputStream((count++)+".part");
68             fos.write(buf,0,len);
69             fos.close();
70         }        
71         fis.close();        
72     }
73 }

管道流

在Java中,可以使用管道流进行线程之间的通信,输入流和输出流必须相连接

字节流:管道输出流PipedOutputStream,管道输入流PipedInputStream

字符流:管道输出流PipedWriter,管道输入流PipedReader

 1 import java.io.*;
 2 class Read implements Runnable
 3 {
 4     private PipedInputStream in;
 5     Read(PipedInputStream in)
 6     {
 7         this.in = in;
 8     }
 9     public void run()
10     {
11         try
12         {
13             byte[] buf = new byte[1024];
14 
15             System.out.println("读取前。。没有数据阻塞");
16             int len = in.read(buf);
17             System.out.println("读到数据。。阻塞结束");
18 
19 
20             String s= new String(buf,0,len);
21             System.out.println(s);
22 
23             in.close();
24         }
25         catch (IOException e)
26         {
27             throw new RuntimeException("管道读取流失败");
28         }
29     }
30 }
31 class Write implements Runnable
32 {
33     private PipedOutputStream out;
34     Write(PipedOutputStream out)
35     {
36         this.out = out;
37     }
38     public void run()
39     {
40         try
41         {
42             System.out.println("开始写入数据,等待6秒后。");
43             Thread.sleep(6000);
44             out.write("piped lai la".getBytes());
45             out.close();
46         }
47         catch (Exception e)
48         {
49             throw new RuntimeException("管道输出流失败");
50         }
51     }
52 }
53 class  PipedStreamDemo
54 {
55     public static void main(String[] args) throws IOException
56     {
57 
58         PipedInputStream in = new PipedInputStream();
59         PipedOutputStream out = new PipedOutputStream();
60         in.connect(out);
61 
62         Read r = new Read(in);
63         Write w = new Write(out);
64         new Thread(r).start();
65         new Thread(w).start();
66     }
67 }

内存操作流

假设有一些临时的信息要求通过IO操作的话,那么如果将这些临时的信息保存在文件之中则肯定很不合理,因为操作的最后还要把文件再删除掉,所以此时的IO中就提供了一个内存的操作流,通过内存操作流输入和输出的目标是内存。

字节流:内存字节数组输入流ByteArrayInputStream,内存字节数组输出流ByteArrayOutputStream。

字符流:内存字符数组输入流CharArrayReader,内存字符数组输出流CharArrayWriter。

           内存字符串输入流StringReader,内存字符串输出流StringWriter。

 1 import java.io.*;
 2 class ByteArrayStream 
 3 {
 4     public static void main(String[] args) 
 5     {
 6         //数据源。
 7         ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());
 8 
 9         //数据目的
10         ByteArrayOutputStream bos = new ByteArrayOutputStream();
11 
12         int by = 0;
13         while((by=bis.read())!=-1)
14         {
15             bos.write(by);
16         }
17         System.out.println(bos.size());
18         System.out.println(bos.toString());
19     //    bos.writeTo(new FileOutputStream("a.txt"));
20     }
21 }

 

对象的序列化

对 于一个存在Java虚拟机中的对象来说,其内部的状态只是保存在内存中。JVM退出之后,内存资源也就被释放,Java对象的内部状态也就丢失了。而在很 多情况下,对象内部状态是需要被持久化的,将运行中的对象状态保存下来(最直接的方式就是保存到文件系统中),在需要的时候可以还原,即使是在Java 虚拟机退出的情况下。
对象序列化机制是Java内建的一种对象持久化方式,可以很容易实现在JVM中的活动对象与字节数组(流)之间进行转换,使用得Java对象可以被存储, 可以被网络传输,在网络的一端将对象序列化成字节流,经过网络传输到网络的另一端,可以从字节流重新还原为Java虚拟机中的运行状态中的对象。

把Java对象转换为字节序列的过程称为对象的序列化。对象序列化包括如下步骤:
1) 创建一个对象输出流java.io.ObjectOutputStream,它可以包装一个其他类型的目标输出流,如文件输出流;
2) writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。 

把字节序列恢复为Java对象的过程称为对象的反序列化。对象反序列化的步骤如下:
1) 创建一个对象输入流java.io.ObjectInputStream,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

注 意:只有实现了Serializable和Externalizable接口的类的对象才能被序列化,声明为static和transient类型的成 员数据不能被序列化。Serializable接口内没有任何方法,只是一个标记接口,采用默认的方式保存所有对象。Externalizable接口继承自Serializable接口,实现Externalizable接口的类可以由开发人员决定保存的对象(实现此接口的类必须定义一个无参构造函数)。

Person类继承了Serializable

 1 import java.io.*;
 2 class Person implements Serializable
 3 {
 4     /*
 5     显式地定义serialVersionUID
 6     在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
 7     在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。
 8     */
 9     public static final long serialVersionUID = 42L;
10 
11     private String name;
12     transient int age;
13     static String country = "cn";
14     Person(String name,int age,String country)
15     {
16         this.name = name;
17         this.age = age;
18         this.country = country;
19     }
20     public String toString()
21     {
22         return name+":"+age+":"+country;
23     }
24 }

对Person类对象进行序列化和反序列化

 1 import java.io.*;
 2 class ObjectStreamDemo 
 3 {
 4     public static void main(String[] args) throws Exception
 5     {
 6         //writeObj();//序列化
 7         readObj();//反序列化
 8     }
 9     public static void readObj()throws Exception
10     {
11         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
12 
13         Person p = (Person)ois.readObject();
14 
15         System.out.println(p);
16         ois.close();
17     }
18     public static void writeObj()throws IOException
19     {
20         ObjectOutputStream oos = 
21             new ObjectOutputStream(new FileOutputStream("obj.txt"));
22 
23         oos.writeObject(new Person("lisi0",399,"kr"));
24         oos.close();
25     }
26 }

 

 

 

 

 

 

 

 

posted on 2013-08-06 12:08  xscn  阅读(508)  评论(0编辑  收藏  举报