首页 > 代码库 > 黑马程序员——【Java基础】——Java IO流

黑马程序员——【Java基础】——Java IO流

一、IO概述

  1、IO:是Input、Output的缩写。

  2、特点:

  (1)用于处理设备间的数据传输。

  (2)Java对数据的处理是通过“流”完成的。

  (3)Java用于操作流的对象都在IO包中。

  (4)流按操作分为两种:字节流和字符流。

  (5)流按流向分为:输入流和输出流(输入输出是相对于“内存”而言的)。

  3、IO流常用基类

  (1)字节流abstract基类:InputStream、OutputStream;

  (2)字符流抽象基类:Reader、Writer;

二、字符流(Reader、Writer

  (一)概述

  字符流只用于处理文字数据,是字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字。简单说:字符流 = 字节流+编码表

  (二)写入字符流(Writer

  1、“写入字符流”操作步骤

  (1)创建时,要明确文件存储路径。如果文件不存在,则自动创建文件。如果文件存在,则会覆盖原文件。代码示例:

    FileWtriter fw = new FileWriter("d:\\d.txt");

  (2)调用Writer对象中的write(String s)方法,将数据写入到“临时存储缓冲区”中。代码示例:

    fw.write("abcde");

  (3)调用flush()方法,刷新该流的缓冲,将数据刷新到目的地中。代码示例:

    fw.flush(); //可以用多次

  (4)调用close()方法,关闭流资源。代码示例:

    fw.close();//但是关闭前会刷新一次内部的缓冲数据,并将数据刷新到目的地中,只能用一次。

  注意:close()和flush()区别:flush()刷新后,流可以继续使用;而close()刷新后,将会关闭流,不可再写入字符流。

  2、FileWriter细节

  (1)换行

  Windows系统中的换行是\r\n,而Linux系统中的换行是\n。为了能够适应不同的操作系统,java可以获取系统换行。格式如下

    System.getProperty(“line.sepatator”);

  (2)续写

  如果再FileWriter的构造函数中加入true,可以实现对文件实行续写。格式如下:

    FileWtriter fw = new FileWriter("d:\\d.txt" , true);

  (3)IO异常处理

  将FileWriter对象(FileWriter fw = null)声明在try{}catch(){}外面。

  在finally中,关闭流对象,判断fw是否为空,不为空时,才可以用try{}catch(){}来处理fw.close()。否则,会出现java.lang.NullPointerException。

  3、FileWriter总结

  (1)其实java自身不能写入数据,而是调用系统内部方式完成数据的书写,使用系统资源后,一定要关闭资源。

  (2)文件的数据的续写是通过构造函数 FileWriter(Strings,boolean append),在创建对象时,传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。(windows系统中的文件内换行用\r\n两个转义字符表示,在linux系统中只用\n表示换行)

  (3)由于在创建对象时,需要指定创建文件位置,如果指定的位置不存在,就会发生IOException异常,所以在整个步骤中,需要对IO异常进行try处理。

  (三)读取字符流(Reader

  1、“读取字符流”操作步骤

  (1)创建一个文件读取流对象,和指定名称的文件相关联。要保证该文件已经存在,若不存在,将会发生异常FileNotFoundException。代码示例:

    FileReader fr = new FileReader(“d:\\demo.txt”);

  (2)调用读取流对象的read()方法。read()有两种读取方式:一种是读取单个字符。另一种是通过字符数组进行读取。两种读取方式的代码示例:

    ① 读取单个字符方式:int ch = fr.read();

    ② 读取字符数组方式: 

1 char[] buf = new char[1024];2 Int len = 0;3 While(( len = fr.read(buf))!=-1){4     System.out.print( new String(buf , 0 , len));5 }

  (3)读取后调用close()方法,关闭流资源。代码示例:

    fr.close();

  2、FileReader总结

  (1)定义文件路径时,可以用“/”或者“\\”。

  (2)在创建一个文件时,如果目录下有同名文件将被覆盖。

  (3)在读取文件时,必须保证该文件已存在,否则出异常。

  (四)字符流练习:

  /*

  需求:将c盘一个文本文件复制到d盘。

  思路:1、需要读取源;2、将读到的源写入到目的地;

  步骤:

  1、读一个文件,是字符读取流和文件关联;

  2、创建一个目的文件,用于存储读到的数据;

  3、频繁的读写;

  4、关闭流资源;

  */

 1 import java.io.*; 2 class ReaderWriterTest { 3     public static void main(String[] args) { 4         // 调用复制方法 5         // copy_1(); 6         copy_2(); 7     } 8     // 用第一种读取方式进行复制 9     public static void copy_1() {10         FileWriter fw = null;11         FileReader fr = null;12         try {13             // 关联读取和写入的文件14             fw = new FileWriter("D:\\HelloWorld.java");15             fr = new FileReader("C:\\HelloWorld.java");16             for (int ch = 0; (ch = fr.read()) != -1;) {17                 fw.write(ch);// 一个字符一个字符写入18             }19         } catch (IOException e) {20             throw new RuntimeException("读写失败");21         } finally {22             if (fr != null)23                 try {24                     fr.close();// 对读取流和写入流分别关闭25                 } catch (IOException e) {26                 }27             if (fw != null)28                 try {29                     fw.close();30                 } catch (IOException e) {31                 }32         }33     }34     // 第二种读取方式进行复制35     public static void copy_2() {36         FileWriter fw = null;37         FileReader fr = null;38         try {39             // 关联读取和写入的文件40             fw = new FileWriter("D:\\HelloWorld.java");41             fr = new FileReader("C:\\HelloWorld.java");42             char[] arr = new char[1024];43             for (int len = 0; (len = fr.read(arr)) != -1;) {44                 fw.write(arr, 0, len);// 利用数组一次存入数组中的字符45             }46         } catch (IOException e) {47             throw new RuntimeException("读写失败");48         } finally {49             try {50                 if (fr != null)51                     fr.close();52             } catch (IOException e) {53             } finally {54                 if (fw != null)55                     try {56                         fw.close();57                     } catch (IOException e) {58                     }59             }60         }61     }62 }

三、字符流缓冲区

  (一)概述

  1、字符流缓冲区的作用:提高了对数据的读写效率。

  2、对应的类:BufferedWriter以及BufferedReader,要结合流,才可以使用。

  (二)BufferedWriter

  1、操作步骤

  (1)创建一个字符写入流对象,代码示例:

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

  (2)为了提高字符写入流效率,加入缓冲技术,将需要被提高效率的流对象作为参数传递给缓冲区的构造函数,代码示例:

    BufferedWriter bufw = new BufferedWriter(fw);

  (3)调用write方法写入数据到指定文件,代码示例:

    bufw.write ("abcde");

  (4)刷新缓冲区,代码示例:

    bufw.flush();

  (5)关闭流资源,,代码示例:

    bufw.close();

  2、小细节:BufferedWriter提供了跨平台的换行符newLine()方法,格式:bufw.newLine();

  (三)BufferedReader

  1、作用

  从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

  2、特点

  BufferedReader提供了一次读一行的方法readLine(),方便于文本数据的获取,当返回null时表示读到文件末尾。readLine方法返回的时候,只返回回车符之前的数据内容。并不返回回车符。

  3、readLine()原理

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

  4、BufferedReader操作步骤

  (1)创建一个读取流对象和文件相关联,

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

  (2)为了提高效率、加入缓冲技术、将字符读取流对象作为参数传递给缓冲区对象的构造函数。

    BufferedReader bufr = new BufferedReader(fr);

  (3)调用该readLine()方法一行一行读取,如果到达文件末尾,则返回null

    String str = bufr.readLine();

  (4)关闭流资源

    bufr.close();

  (四)练习

  /* 需求:使用缓冲技术copy一个文本文件 */ 

import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class CopyTextByBufTest {    public static void main(String[] args) throws IOException {        FileReader fr = new FileReader("buf.txt");        BufferedReader bufr = new BufferedReader(fr);        FileWriter fw = new FileWriter("buf_copy.txt");        BufferedWriter bufw = new BufferedWriter(fw);        String line = null;        while((line=bufr.readLine())!=null){            bufw.write(line);            bufw.newLine();            bufw.flush();        }//单个字符读取方式        //int ch = 0;        //while((ch=bufr.read())!=-1){        //    bufw.write(ch);        //}        bufw.close();        bufr.close();    }}

  (五)自定义缓冲区

 1 /*需求:模拟BufferedReader,自定义一个MyBufferedReader缓冲区 */ 2 import java.io.*; 3 //自定义缓冲类   4 class MyBufferedReader extends Reader { 5     private Reader r;// 定义接收的流对象 6     MyBufferedReader(Reader r) { 7         this.r = r; 8     } 9     // 自定义整行读取10     public String myReadLine() throws IOException {11         // 创建一个容器,用来存储一行的字符12         StringBuilder sb = new StringBuilder();13         // 一个字符一个字符读取14         for (int ch = 0; (ch = r.read()) != -1;) {15             if (ch == ‘\r‘)// 如果遇到换行符,则继续16                 continue;17             if (ch == ‘\n‘)// 如果遇到回车符,表示该行读取完毕18                 return sb.toString();19             else20                 sb.append((char) ch);// 将该行的字符添加到容器21         }22         if (sb.length() != 0)// 如果读取结束,容器中还有字符,则返回元素23             return sb.toString();24         return null;25     }26     // 复写父类中的抽象方法27     public int read(char[] cbuf, int off, int len) throws IOException {28         return r.read(cbuf, off, len);29     }30     // 复写父类的close方法31     public void close() throws IOException {32         r.close();33     }34 }35 36 // 测试MyBufferedReader37 class MyBufferedReaderDemo {38     public static void main(String[] args) {39         MyBufferedReader mbr = null;40         try {41             mbr = new MyBufferedReader(new FileReader("d:\\HelloWorld.java"));42             for (String line = null; (line = mbr.myReadLine()) != null;) {43                 System.out.println(line);// 显示效果44             }45         } catch (IOException e) {46             throw new RuntimeException("读取数据失败");47         } finally {48             try {49                 if (mbr != null)50                     mbr.close();51             } catch (IOException e) {52                 throw new RuntimeException("读取流关闭失败");53             }54         }55     }56 }

  (六)LineNumberReader

  在BufferedReader中有个直接的子类LineNumberReader,其中有特有的方法获取和设置行号:

  setLineNumber();//设置初始行号

  getLineNumber();//获取行号

  (七)装饰设计模式

  1、对一组对象的功能进行增强时,就可以使用装饰模式来解决问题。

  2、特点:装饰类通常都会通过构造方法接收被装饰的对象,基于被装饰的对象的功能,提供更强的功能。

  3、“装饰和继承”的异同?

  (1)相同点:进行功能的扩展和增强,

  (2)区别:装饰模式比继承要灵活、避免了继承体系的臃肿,降低了类与类之间的继承关系。装饰类和被装饰的类通常都是属于一个体系,有同一个接口或父类。

  注:在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。

 

 

 

 

黑马程序员——【Java基础】——Java IO流