黑马程序员技术交流社区

标题: 【阳哥笔记】极速秒杀Java基础之笔记系列—Day21( IO )! [打印本页]

作者: 阳哥忠粉    时间: 2015-6-7 15:29
标题: 【阳哥笔记】极速秒杀Java基础之笔记系列—Day21( IO )!


笔记总链接:http://bbs.itheima.com/thread-200600-1-1.html

8、IO

8.2 IO流

    8.2.2 IO流常用基类-字符流

    练习:
    将d盘的一个文本文件复制到d盘。

    分析:
    读取d盘demo.txt文件中的数据,将这些数据写入到d盘copyText_1.txt文件当中。既然是操作文本数据,使用字符流。


    方式1:使用read()读取文本文件数据。

    代码:
  1. import java.io.FileReader;
  2. import java.io.FileWriter;
  3. import java.io.IOException;

  4. public class CopyTextTest{
  5.        public static void main(String[] args) throws IOException {
  6.              //1、读取一个已有的文本文件,使用字符读取流和文件相关联
  7.             FileReader fr = new FileReader("demo.txt" );

  8.              //2、创建一个目的,用于存储读到数据。
  9.             FileWriter fw = new FileWriter("copyText_1.txt" );

  10.              //3、频繁的读写操作
  11.              int ch = 0;
  12.              while((ch = fr.read()) != -1){
  13.                   fw.write(ch);
  14.             }
  15.             
  16.              //4、关闭字节流
  17.             fw.close();
  18.             fr.close();
  19.       }
  20. }
复制代码
   运行结果:





    方式2:使用read(char[])读取文本文件数据。

    代码:
  1. import java.io.FileReader;
  2. import java.io.FileWriter;
  3. import java.io.IOException;

  4. public class CopyTextTest{
  5.        private static final int BUFFER_SIZE = 1024;

  6.        public static void main(String[] args){
  7.             FileReader fr = null;
  8.             FileWriter fw = null;
  9.             
  10.              try{
  11.                   fr = new FileReader("demo.txt" );
  12.                   fw = new FileWriter("copytest_2.txt" );
  13.                   
  14.                    //创建一个临时容器,用于缓存读取到的字符
  15.                    char[] buf = new char[BUFFER_SIZE];

  16.                    //定义一个变量记录读取到的字符数(其实就是往数组里装的字符个数)
  17.                    int len = 0;

  18.                    while((len = fr.read(buf)) != -1){
  19.                         fw.write(buf,0,len);
  20.                   }
  21.             } catch(Exception e){
  22.                    throw new RuntimeException("读写失败!");
  23.             } finally{
  24.                    if(fw != null){
  25.                          try{
  26.                               fw.close();
  27.                         } catch(IOException e){
  28.                               System.out.println(e.toString());
  29.                         }
  30.                   }
  31.                    if(fr != null){
  32.                          try{
  33.                               fw.close();
  34.                         } catch(IOException e){
  35.                               System.out.println(e.toString());
  36.                         }
  37.                   }
  38.             }
  39.       }
  40. }
复制代码
   运行结果:





    字符流的缓冲区
    缓冲区的出现提高了对数据的读写效率。

    对应类:
   BufferedWriter
   BufferedReader


    P.S.
    缓冲区要结合流才可以使用。

    作用:在流的基础上对流的功能进行了增强。


    示例6:提高写入效率,使用缓冲区。
  1. import java.io.BufferedWriter;
  2. import java.io.FileWriter;
  3. import java.io.IOException;

  4. public class BufferedWriterDemo{
  5.        public static void main(String[] args) throws IOException{
  6.             FileWriter fw = new FileWriter("buf.txt" );

  7.              //为了提高写入的效率,使用了字符流的缓冲区
  8.              //创建了一个字符写入流的缓冲区对象,并且指定与要被缓冲的流对象相关联
  9.             BufferedWriter bufw = new BufferedWriter(fw);

  10.              for(int x = 1; x <= 4; x++){
  11.                    //使用缓冲区的写入方法将数据先写入到缓冲区中
  12.                   bufw.write( "abcdef" + x);
  13.                    //写入内容换行方法:newLine();
  14.                   bufw.newLine();
  15.                   bufw.flush();
  16.             }

  17.              //使用缓冲区的刷新方法将数据刷目的地中
  18.             bufw.flush();

  19.              //关闭缓冲区,其实关闭的就是被缓冲的流对象
  20.             fw.close();
  21.       }
  22. }
复制代码
   运行结果:





    示例7:提高读取效率,使用缓冲区。
  1. import java.io.BufferedReader;
  2. import java.io.FileNotFoundException;
  3. import java.io.FileReader;

  4. public class BufferedReaderDemo{
  5.        public static void main(String[] args) throws Exception{
  6.             FileReader fr = new FileReader("buf.txt" );
  7.             
  8.             BufferedReader bufr = new BufferedReader(fr);

  9.             String line = null;

  10.              while((line = bufr.readLine()) != null){
  11.                   System.out.println(line);           
  12.             }

  13.             bufr.close();
  14.       }
  15. }
复制代码
   运行结果:

    字符流缓冲区:

    写入换行使用BufferedWriter类中的newLine()方法。
    读取一行数据使用BufferedReader类中的readLine()方法。

    bufr.read():这个read方法是从缓冲区中读取字符数据,所以覆盖了父类中的read方法。
    bufr.readLine():另外开辟了一个缓冲区,存储的是原缓冲区一行的数据,不包含换行符。


    原理:使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记,将标记前的缓冲数据变成字符串返回。

    示例8:
  1. import java.io.BufferedReader;
  2. import java.io.BufferedWriter;
  3. import java.io.FileReader;
  4. import java.io.FileWriter;

  5. public class CopyTextBufTest{
  6.        public static void main(String[] args) throws Exception {
  7.             FileReader fr = new FileReader("buf.txt" );
  8.             BufferedReader bufr = new BufferedReader(fr);

  9.             FileWriter fw = new FileWriter("buf_copy.txt" );
  10.             BufferedWriter bufw = new BufferedWriter(fw);
  11.             
  12.             String line = null;

  13.              //方式一
  14.              while((line = bufr.readLine()) != null){
  15.                   bufw.write(line);
  16.                   bufw.newLine();
  17.                   bufw.flush();
  18.             }

  19.              //方式二
  20.              /*
  21.             int ch = 0;

  22.             while((ch = bufr.read()) != -1){
  23.                   bufw.write(ch);
  24.             }
  25.             */

  26.             bufr.close();
  27.             bufw.close();
  28.       }
  29. }
复制代码
   运行结果:




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

    示例:
  1. import java.io.FileReader;
  2. import java.io.IOException;
  3. import java.io.LineNumberReader;

  4. public class LineNumberReaderDemo{
  5.        public static void main(String[] args) throws IOException {
  6.             FileReader fr = new FileReader("LineNumberReaderDemo.java" );
  7.             LineNumberReader lnr = new LineNumberReader(fr);
  8.       
  9.             String line = null;
  10.             
  11.             lnr.setLineNumber(100);

  12.              while((line = lnr.readLine()) != null){
  13.                   System.out.println(lnr.getLineNumber() + ":" + line);
  14.             }

  15.             lnr.close();
  16.       }
  17. }
复制代码
   运行结果:

    8.2.3 装饰设计模式
    对原有类进行了功能的改变,增强。
    示例:
  1. class Person{
  2.        void chifan(){
  3.             System.out.println( "吃饭");
  4.       }
  5. }

  6. //采用装饰的方式增强Person类
  7. //这个类的出现是为了增强Person而出现的
  8. class NewPerson{
  9.        private Person p;

  10.       NewPerson(Person p){
  11.              this.p = p;
  12.       }

  13.        public void chifan(){
  14.             System.out.println( "开胃酒");
  15.             p.chifan();
  16.             System.out.println( "甜点");
  17.       }
  18. }

  19. //采用继承的方式增强Person类
  20. class NewPerson2 extends Person{
  21.        public void chifan(){
  22.             System.out.println( "开胃酒");
  23.              super.chifan();
  24.             System.out.println( "甜点");
  25.       }
  26. }

  27. public class PersonDemo{
  28.        public static void main(String[] args){
  29.             Person p = new Person();
  30.             NewPerson np1 = new NewPerson(p);
  31.             np1.chifan();

  32.             System.out.println( "---------------");

  33.             NewPerson2 np2 = new NewPerson2();
  34.             np2.chifan();
  35.       }
  36. }
复制代码
   运行结果:

    装饰和继承都能实现一样的特点:进行功能的扩展增强。有什么区别呢?

    首先有一个继承体系:
    Writer
          |--TextWriter:用于操作文本
          |--MediaWriter:用于操作媒体
    如果想要对操作的动作进行效率的提高,按照面向对象,可以通过继承的方式对具体的对象进行功能的扩展,那么就需要加入缓冲技术。
    Writer
          |--TextWriter:用于操作文本
               |--BufferTextWriter:加入了缓冲技术的操作文本的对象
          |--MediaWriter:用于操作媒体
               |--BufferMediaWriter:加入了缓冲技术的操作媒体的对象
    以上方式并不理想,如果这个体系需要再进行功能扩展,又多了更多流对象。
    这样就会发现只为提高功能,导致继承体系越来越臃肿,不够灵活。

    重新思考问题:
    既然加入的都是同一种技术--缓冲。
    前一种是让缓冲和自己的流对象相结合。
    可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将哪个对象和缓冲关联。
  1. class Buffer {
  2.      Buffer(TextWriter w){}
  3.      Buffer(MediaWriter w){}
  4. }
复制代码
   简化为:

  1. class BufferedWriter extends Writer{
  2.      BufferedWriter(Writer w){}
  3. }
复制代码

    Writer
         |--TextWriter:用于操作文本
         |--MediaWriter:用于操作媒体
         |--BufferedWriter:用于提高效率

    可见:装饰比继承灵活。
    特点:装饰类和被装饰类都必须所属同一个接口或者父类。

    练习:
    自定义一个读取缓冲区类,模拟一个BufferedReader。

    分析:
    缓冲区中无非就是封装了一个数组,并对外提供了更多的方法对数组进行访问,其实这些方法最终操作的都是数组的角标。

    缓冲的原理:
    其实就是从源中获取一批数据到缓冲区中,再从缓冲区中不断地取出一个一个数据。
    在此次取完后,再从源中继续取一批数据进缓冲区,当源中的数据取完时,用-1作为结束标记。

    代码:
  1. import java.io.FileReader;
  2. import java.io.IOException;
  3. import java.io.Reader;

  4. class MyBufferedReader{
  5.       
  6.       private Reader r;
  7.       
  8.       //定义一个数组作为缓冲区
  9.       private char[] buf = new char[1024];

  10.       //定义一个指针用于操作这个数组中的元素,当操作到最后一个元素后,指针应该归零
  11.       private int pos = 0;

  12.       //定义一个计数器用于记录缓冲区中的数据个数,当该数据减到0,就从源中继续获取数据到缓冲区中
  13.       private int count = 0;

  14.       MyBufferedReader(Reader r){
  15.              this .r = r;
  16.       }
  17.       
  18.       //该方法从缓冲区中一次取一个字符
  19.       public int myRead() throws IOException {
  20.              //从源中获取一批数据到缓冲区中,需要先做判断,只有计数器为0时,才需要从源中获取数据
  21.              if (count == 0){
  22.                   count = r.read(buf);
  23.       
  24.                   //每次获取数据到缓冲区后,角标归零
  25.                   pos = 0;
  26.              }

  27.              if (count < 0)
  28.                    return -1;

  29.              char ch = buf[pos];

  30.              pos++;
  31.              count--;

  32.              return ch;
  33.       }

  34.        public String myReadLine() throws IOException {
  35.             StringBuilder sb = new StringBuilder();

  36.              int ch = 0;
  37.              while ((ch = myRead()) != -1){
  38.                    if (ch == '\r' )
  39.                          continue ;
  40.                    if (ch == '\n' )
  41.                          return sb.toString();
  42.                    //将从缓冲区读到的字符,存储到缓存行数据的缓冲区中
  43.                   sb.append(( char )ch);
  44.             }
  45.             
  46.              if (sb.length() != 0){
  47.                    return sb.toString();
  48.             }
  49.              return null ;
  50.       }

  51.        public void myClose() throws IOException {
  52.             r.close();
  53.       }
  54. }

  55. public class MyBufferedReaderDemo{
  56.        public static void main(String[] args) throws IOException {
  57.             FileReader fr = new FileReader("buf.txt" );
  58.             
  59.             MyBufferedReader bufr = new MyBufferedReader(fr);

  60.             String line = null ;

  61.              while ((line = bufr.myReadLine()) != null){
  62.                   System.out.println(line);           
  63.             }

  64.             bufr.myClose();
  65.       }
  66. }
复制代码
    运行结果:

    8.2.4 IO流常用基类-字节流

    基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。

    示例1:
  1. import java.io.FileOutputStream;
  2. import java.io.IOException;

  3. public class ByteStreamDemo{
  4.        public static void main(String[] args) throws IOException {
  5.             demo_write();
  6.       }

  7.        public static void demo_write() throws IOException {
  8.              //1、创建字节输出流对象,用于操作文件
  9.             FileOutputStream fos = new FileOutputStream( "bytedemo.txt");

  10.              //2、写数据,直接写入到了目的地中
  11.             fos.write( "abcdefg".getBytes());
  12.       
  13.              //关闭资源动作要完成
  14.             fos.close();
  15.       }
  16. }
复制代码
   运行结果:





    示例2:
  1. import java.io.FileInputStream;
  2. import java.io.IOException;

  3. public class ByteStreamDemo{
  4.        public static void main(String[] args) throws IOException {
  5.             demo_read1();
  6.             System.out.println( "---------------");
  7.             demo_read2();
  8.             System.out.println( "---------------");
  9.             demo_read3();
  10.       }

  11.        //读取方式一
  12.        public static void demo_read1() throws IOException {
  13.              //1、创建一个读取流对象,和指定文件关联
  14.             FileInputStream fis = new FileInputStream("bytedemo.txt" );
  15.             
  16.              //打印字符字节大小,不过要少用,文件太大,可能内存溢出
  17.              byte[] buf = new byte[fis.available()];
  18.             fis.read(buf);
  19.             System.out.println( new String(buf));
  20.             
  21.             fis.close();
  22.       }
  23.       
  24.        //读取方式二
  25.        public static void demo_read2() throws IOException {
  26.             
  27.              FileInputStream fis = new FileInputStream("bytedemo.txt" );
  28.             
  29.              //建议使用这种读取数据的方式
  30.              byte[] buf = new byte[1024];

  31.              int len = 0;

  32.              while((len = fis.read(buf)) != -1){
  33.                   System.out.println( new String(buf,0,len));
  34.             }

  35.             fis.close();
  36.       }
  37.       
  38.        //读取方式三
  39.        public static void demo_read3() throws IOException {
  40.             
  41.             FileInputStream fis = new FileInputStream("bytedemo.txt" );
  42.             
  43.              //一次读取一个字节
  44.              int ch = 0;
  45.              while((ch = fis.read()) != -1){
  46.                   System.out.print(( char)ch);
  47.             }
  48.             
  49.             fis.close();
  50.       }
  51. }
复制代码
    运行结果:

    P.S.
    FileOutputStream、FileInputStream的flush方法内容为空,没有任何实现,调用没有意义。

    字节流的缓冲区:同样是提高了字节流的读写效率。

    练习:
    通过几种方式对MP3的进行拷贝,比较它们的效率。

    代码:
  1. import java.io.BufferedInputStream;
  2. import java.io.BufferedOutputStream;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;

  6. public class CopyMp3Test{
  7.        public static void main(String[] args) throws IOException {
  8.             copy_1();
  9.             copy_2();
  10.       }

  11.        public static void copy_1() throws IOException {
  12.             FileInputStream fis = new FileInputStream("0.mp3" );
  13.             FileOutputStream fos = new FileOutputStream("1.mp3" );
  14.       
  15.              byte[] buf = new byte[1024];

  16.              int len = 0;

  17.              while((len = fis.read(buf)) != -1){
  18.                   fos.write(buf,0,len);
  19.             }

  20.             fis.close();
  21.             fos.close();
  22.       }

  23.        public static void copy_2() throws IOException {
  24.             FileInputStream fis = new FileInputStream("0.mp3" );
  25.             BufferedInputStream bufis = new BufferedInputStream(fis);

  26.             FileOutputStream fos = new FileOutputStream("2.mp3" );
  27.             BufferedOutputStream bufos = new BufferedOutputStream(fos);

  28.              int ch = 0;

  29.              while((ch = bufis.read()) != -1){
  30.                   bufos.write(ch);
  31.             }

  32.             bufis.close();
  33.             bufos.close();
  34.       }
  35. }
复制代码
   运行结果:



~END~




作者: 流水0215    时间: 2015-6-9 09:14
占个沙发,支持楼主
作者: 那一世的苍白    时间: 2015-6-9 17:14
学习学习
作者: 熊乾坤    时间: 2015-6-9 22:12
继续支持!!!
作者: cyd1058    时间: 2015-6-9 22:48
更新很快!膜拜
作者: 魏海洲    时间: 2015-6-12 22:31
学习学习
作者: javazhang    时间: 2015-6-16 17:56
坚持学习,支持群主
作者: wenweishan2015    时间: 2015-6-17 01:00
赞一个!!!
作者: javazhang    时间: 2015-6-21 10:18
真的的每次都能学到一点新的收货
作者: 魏海洲    时间: 2015-6-22 21:34
坚持学习,支持群主
作者: 十五号的人生    时间: 2015-6-22 21:42
马上就要开始学了,先看看,谢楼主
作者: Z、c    时间: 2015-7-3 11:14
IO流方法好多啊:D
作者: 星痕-凌    时间: 2015-7-5 09:35
zan  zan  zan zan !!!
作者: 星痕-凌    时间: 2015-7-6 22:56
超赞的说——————!正好需要!!!!!!!!!!!!!!!!!
作者: Z、c    时间: 2015-7-7 00:44
新的一天,签完到去睡了
作者: 星痕-凌    时间: 2015-7-16 22:05
还没学到,先下载下来,学到看!!!!!!!!!
作者: 放心飞    时间: 2015-8-31 17:18
呵呵,有看完了,越来越喜欢充满挑战的任务!
作者: Smilexs    时间: 2015-9-29 16:30
我夜良辰顶起!!
作者: yqlbd    时间: 2015-11-17 09:21
非常感谢啊。
作者: 切比雪夫    时间: 2015-11-18 22:05
支持一下!!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2