黑马程序员__Day03_java基础__IO流

--------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Unity开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

 

IO流

当程序需要读取或写入数据的时候,就会开启一个数据源的流,这个数据源可以是文件,内存,或是网络连接。

 

流的分类:

1,按数据方向分:输入流和输出流

输入流:Reader / InputStream

输出流:Writer / OutputStream

2,按数据类型分:字节流和字符流

字节流:InputStream / OutputStream

|-- FileOutputStream

|-- FileInputStream

缓冲技术

|-- BufferedInputStream 

|-- BufferedOutputStream

字符流:Reader / Writer

|-- FileReader

|-- FileWriter

缓冲技术

|-- BufferedReader    字符读取流缓冲区

|-- BufferedWriter  字符写入流缓冲区

转换流

OutputStreamWriter :将输出的字符流转化为字节流

InputStreamReader :将输入的字节流转换为字符流

例://源,键盘

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

注意:不管如何操作,最后都是以字节的形式保存在文件中的。

 

转换流什么时候使用?

是字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。

例:

按照指定的编码表(UTF-8)存到文件中使用下面的方法

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\123\\d.txt","UTF-8")));

 

管道流

管道输出流:PiPedOutputStream

管道输入流:PipedInputStream

打印流

PrintStream

为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException

合并流

SequenceInputStream :(Enumeration<? extends InputStream> e)

将多个流合并成一个,然后再输出到指定位置

例:

将三个文本文件中内容合并成一个文件。

思路:读取一个文本就会创建一个流。把这些流放在集合中。

  1.   Vector<FileInputStream> v = new Vector<FileInputStream>();  
  2.   
  3.     v.add(new FileInputStream("d:\\123\\1.txt"));  
  4.     v.add(new FileInputStream("d:\\123\\2.txt"));  
  5.     v.add(new FileInputStream("d:\\123\\3.txt"));  
  6.   
  7.     Enumeration<FileInputStream> en = v.elements();  
  8.   
  9.    //SequenceInputStream 只接收 Enumeration(枚举)所以在选用集合时选能实现枚举的  
  10.     SequenceInputStream sis = new SequenceInputStream(en);  
  11.   
  12.     FileOutputStream fos = new FileOutputStream("d:\\123\\123.txt");  
  13.   
  14.     byte[] buf = new byte[1024];  
  15.     int len = 0;  
  16.     while ((len=sis.read(buf))!=-1)  
  17.     {  
  18. fos.write(buf,0,len);  
  19.     }  
  20.   
  21.     fos.close();  
  22.     sis.close();  

 

操作字节数组的流对象

ByteArrayInputStream   

在构造的时候,需要接收数据源,而且数据源是一个字节数组。

例:

ByteArrayInputStream bis = new ByteArrayInputStream("abcd".getBytes());

 

ByteArrayOutputStream

     在构造时,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。

     例:

      ByteArrayOutputStream bos = new ByteArrayOutputStream();

           int by = 0;

while ((by=bis.read())!=-1)

{

  bos.write(by);

}

System.out.println(bos.toString());

操作字符数组

CharArrayReader

CharArrayWriter  用法一样

操作字符串

StringReader

StringWriter

操作基本数据类型的流对象

DataInputStreamgn 

DataOutputStream

Properties 

操作于集合和IO流之间, Properties 继承于 Hashtable

 

缓冲区技术

缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。

例:

使用写入流缓冲区技术

//1,创建一个字符写入流对象

FileWriter fw = new FileWriter("buf.txt");

//2,为了提高写入流效率,加入缓冲技术

BufferedWriter bufw = new BufferedWriter(fw);

这样就可以使用缓冲技术的方法,如:newLine()  换行,使用这个具有跨平台性。

 

注意: bufw.close();  //底层操作其实就是fw流,所以只要关闭缓冲区就是关闭fw

例:

复制一个Mp3,通过字节流的 缓冲区完成复制

  1. public void method() throws IOException  
  2. {  
  3.     BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("D:\\123\\Honey.mp3"));  
  4.     BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("D:\\123\\123.mp3"));  
  5.   int by = 0;  
  6.     while ( (by=bfis.read()) !=-1 )    
  7.     {  
  8.         bfos.write(by);  
  9.     }  
  10.         bfis.close();  
  11.         bfos.close();  
  12. }   

例:复制一个图片,不用缓冲区,使用数组完成,

  1. public void method2() throws IOException  
  2. {  
  3.       FileInputStream fis = new FileInputStream("D:\\123\\1.jpg");  
  4.       FileOutputStream fos = new FileOutputStream("D:\\123\\2.jpg");  
  5.   
  6.       byte[] buf = new byte[1024];  // 这里数组其实就相当于是缓冲区  
  7.       int len = 0;  
  8.       while ((len=fis.read(buf))!=-1)  
  9.       {  
  10.       fos.write(buf,0,len);  
  11.     }  
  12.   
  13.       fis.close();  
  14.    fos.close();  
  15. }  

 

自定义缓冲区技术:

实现原理:

使用底层InputStream  read 方法,将数据存入到缓冲区(数组)中,我们从缓冲区读数据是从数组中读取数据,当该数组中读完后,让read方法在读一次,把读到的数据存入到缓冲区中,。。。这样循环,直到,把数据源中的数据读完。

 

这里以定义 字节流缓冲区 为例

  1. class MyBufferedInputStream   
  2. {  
  3.     private InputStream in;  
  4.     private byte[] buf = new byte[1024];  //缓冲区,  
  5.     private int pos = 0,count = 0;  //计数器,指针  
  6.     MyBufferedInputStream(InputStream in)   
  7.     {  
  8.         this.in = in;  
  9.     }  
  10.     //调用一次 从缓冲区(字节数组)中读一个字节  
  11.     public int myRead() throws IOException  
  12.     {  
  13.         //通过in对象读取硬盘上数据,并存储在缓冲区buf中  
  14.         if(count==0)  
  15.         {  
  16.             count = in.read(buf);  //采用底层方法读取一批数据存入缓冲区,并返回其个数  
  17.             if(count<0)  
  18.                 return -1;  
  19.             pos = 0;   //指针归位,指向数组0角标开始  
  20.             byte b = buf[pos];   // 指针指向的当前数据  
  21.             count--;  
  22.             pos++;  
  23.             return b&255;  //返回读取到的数据         
  24.         }  
  25.         else if(count>0)  //如果缓冲区还有数据,则取缓冲区中的下一个数据,如缓冲区无数据(count=0时)则让底层read在去读一批数据存入缓冲区,直到读完  
  26.         {  
  27.             byte b = buf[pos];  
  28.             count--;  
  29.             pos++;  
  30.             return b&255;             
  31.         }  
  32.         return -1;  
  33.     }  
  34.     public void myClose() throws IOException  //提供关闭流的方法  
  35.     {  
  36.         in.close();  
  37.     }  
  38.   
  39. }   
  40. /*  
  41. 为什么要与255呢?  
  42.     因为返回类型为int  而byte会自动提升  
  43.     byte 1111  (-1)提升为:  
  44.     int  1111 1111 1111 1111 (还是-1)  
  45.   
  46.               前面填充了1使得一开始while ((by=bfis.myRead())!=-1)不满足没有进行循环  
  47.     所以得填充0  只要与 0000 0000 0000 1111 进行与运算就能保证填充为0  
  48.             1111 1111 1111 1111  
  49.         &   0000 0000 0000 1111  
  50.            ----- -------------------------  
  51.               0000 0000 0000 1111  

 

流对象很多,使用时该用那一个呢?

流操作规律:通过两个明确来完成。

 

1,明确源和目的。

源:输入流。 InputStream(字节流)   Reader(字符流)

目的:输出流。  OutputStream(字节流)  Writer(字符流)

 

2,操作的数据是否是纯文本。

是:使用字符流。

不是:使用字节流。

 

1

将一个文本文件中的数据存储到别一个文件中(复制文件)

 

源: 

用读取流。InputStream   Reader

是文本文件 选Reader

操作文件对象的是 FileReader

 

要提高效率用:加入缓冲区

FileReader fr = new FileReader("a.txt");

BufferedReader bufr = new BufferedReader(fr);

 

目的: 

用 OutputStream   Writer

是纯文本 用Writer

操作文件 FileWriter

 

提高效率用:加入缓冲区

  FileWriter fw = new FileWriter("b.txt");

  BufferedWriter bufw = new BufferedWriter(fw);

 

2

把键盘输入的数据保存到一个文件中。 

 

源:  是纯文本,用Reader

设备:键盘,对应的对象是System.in(字节流)

为了操作键盘的文本数据方便,转成字符流按照字符串操作是最方便的

所以将System.in转换成Reader 即转换流InputStreamReader

InputStreadmReader isr = new InputStreamReader(System.in);

 

提高效率!->缓冲区

BufferedReader bufr = new BufferedReader(isr);

 

目的:是纯文本,用Writer

一个文件,使用FileWriter,当然也可以用OutputStreamWriter

FileWriter fw  = new FileWriter("c.txt");

BufferedWriter bufw = new BufferedWriter(fw);

 

*************************

扩展一下。

想要把录入的数据按照指定的编码表(UTF-8)存到文件中

目的:存储时,需要加入指定编码表。而指定的编码表只有转换流可以指定。

所以要使用的对象是OutputStreamWriter

而该转换流对象要接收一个字节输出流。而且还可以操作谁的的字节输出流FileOutputStream

OutputStreamWriter osw = new OutputStreamWriter( 

new FileOutputStream("d.txt"),"utf-8");

BufferedWriter bufw  = new BufferedWriter(osw);

 

Scanner

可以使用正则表达式来解析基本类型和字符串的简单文本扫描器

Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配。然后可以使用不同的 next 方法将得到的标记转换为不同类型的值。

      Scanner sc = new Scanner(System.in);

      int i = sc.nextInt();

 

File

用于表示文件(目录),通过File类操作硬盘上的文件和目录。File类只用于表示文件的信息(名称,大小等),不能对文件的内容进行访问。

注意:File类的两个常量,如果想实现跨平台,那么最好使用下面的方法来代替分隔符

\ : File.separator

; : File.pathSeparator

 

在创建文件时,如果该目录下已有同名文件,将被覆盖。在写入数据的时候记得要将缓冲区的数据刷新到目的地中。

fw.flush();  //刷新流对象中的缓冲区中的数据,将数据刷新到目的地中

           fw.close();  //关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。

      //将数据刷到目的地中。流关闭后,不能在写入数据。

           close和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭

例:

//列出指定目录下的所有文件名称及其路径

  1.  public static void method_2()  
  2.  {   
  3.         File f = new File("D:\\123");  
  4.           
  5.         File s[] = f.listFiles();  
  6.         for(File fi : s)  
  7.         {  
  8.             System.out.println(fi);  
  9.         }  
  10.     }  
  11.   //列出指定文件类型的文件(如:列出后缀名为.java的文件)  
  12.     public static void method_3()  
  13.     {  
  14.         File f = new File("D:\\123");  
  15.   
  16.         File s[] = f.listFiles(new FilenameFilter()  
  17.         {  
  18.             public boolean accept(File dir,String name)  
  19.             {  
  20.                 return name.endsWith(".txt");  
  21.             }  
  22.         });  
  23.         for(File fi : s)  
  24.         {  
  25.             System.out.println(fi);  
  26.         }  
  27. }  

 

注意:在建立文件时,如果文件存在,继续往里面写入数据,

则传递一个true参数,代表不覆盖已有的文件 ,并在已有文件的末尾进行数据续写

如:fw = new FileWriter("D:\\123\\demo.txt",true);

文本文件中的换行语句  \r\n 

      FileDialog :选择文件对话框窗口 

System

System 类包含一些有用的类字段和方法。它不能被实例化。

在 System 类提供的设施中,有标准输入、标准输出和错误输出流;对外部定义的属性和环境变量的访问;加载文件和库的方法;还有快速复制数组的一部分的实用方法

 

System.in 默认是指键盘录入,还可以自己指定位置

    使用: System.setIn(InputStream in) ;

                如:System.setIn(new FileReader("123.txt")) ;

    源:就被设置成了一个文件

      System.out 输出位置也可设置

                 使用:setOut(PrintStream out) ;

                 如:System.setOut(new FileWriter("222.txt")) ;

     目的:输出位置设置成了一个文件

System.currentTimeMillis(); 返回当前系统时间,以毫秒计算。

 

常见的编码表

ASCII : 美国标准信息交换码。用一个字节的7位可以表示

ISO8859-1 :拉丁码表。欧洲码表。用一个字节的8位表示

GB2312 : 中国的中文编码表。

GBK :中国的中文编码表升级,融合了更多的中文文字符号。

Unicode : 国际标准码,融合了多种文字。

    所有文字都用两个字节来表示,Java语言使用的就是unicode

UTF-8 : 最多用三个字节来表示一个字符。

注意:联通两个字,这两个字的GBK编码,UTF-8的规律相似

 

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Unity开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! --------------------- 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值