首页 > 代码库 > 黑马程序员——【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流