Java面向对象 IO (一)
Java面向对象 IO (一)
知识概要:
(1)IO概述
(2)IO流的常用基类
(3)IO程序的书写
(4)字符流 写入 读取 文本文件的两种读取方式解析(代码演示)
(5)字符流缓冲区
(6)装饰设计模式
IO流概述
IO(Input Output)流
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流 。
流按流向分为:输入流,输出流。
IO流常用基类
字节流的抽象基类:
• InputStream ,OutputStream。
字符流的抽象基类:
• Reader ,Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
• 如:InputStream的子类FileInputStream。
• 如:Reader的子类FileReader。
IO程序的书写
导入IO包中的类
进行IO异常处理
在finally中对流进行关闭
思考:
• 有了垃圾回收机制为什么还要调用close方法进行关闭。
• 为什么IO异常一定要处理。
字符流
字符流和字节流:字节流两个基类:
InputStream OutputStream
字符流两个基类:
Reader Writer
先学习一下字符流的特点。题目如下
既然IO流是用于操作数据的,那么数据的最常见体现形式是:文件。那么先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象。FileWriter。 后缀名是父类名。 前缀名是该流对象的功能。
import java.io.*; class FileWriterDemo { public static void main(String[] args) throws IOException { //创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。 //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。 //其实该步就是在明确数据要存放的目的地。 FileWriter fw = new FileWriter("demo.txt");//本地文件 //调用write方法,将字符串写入到流中。 fw.write("abcde"); //刷新流对象中的缓冲中的数据。 //将数据刷到目的地中。 //fw.flush(); //关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。 //将数据刷到目的地中。 <span style="color:#ff6666;"> //和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。 </span> fw.close(); } }
IO异常的处理方式。
import java.io.*; class FileWriterDemo2 { public static void main(String[] args) { FileWriter fw = null; try { fw = new FileWriter("demo.txt"); fw.write("abcdefg"); } catch (IOException e) { System.out.println("catch:"+e.toString()); } finally { try { if(fw!=null) fw.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }/*
演示对已有文件的数据续写。
*/
import java.io.*; class FileWriterDemo3 { public static void main(String[] args) throws IOException { //传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。 FileWriter fw = new FileWriter("demo.txt",true); fw.write("nihao\r\nxiexie"); fw.close(); } }
文本文件的读取
第一种方式
class FileReaderDemo { public static void main(String[] args) throws IOException { //创建一个文件读取流对象,和指定名称的文件相关联。 <span style="color:#ff0000;"> //要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException </span> FileReader fr = new FileReader("demo.txt"); //调用读取流对象的read方法。 //read():一次读一个字符。而且会自动往下读。 <span style="color:#ff0000;"> int ch = 0; </span> <span style="color:#ff0000;"><span style="color:#000000;"> while((</span>ch=fr.read())!=-1) </span> { System.out.println("ch="+(char)ch); } /* while(true) { int ch = fr.read(); if(ch==-1) break; System.out.println("ch="+(char)ch); } */ fr.close(); } }
第二种方式
/* 第二种方式:通过字符数组进行读取。 */ import java.io.*; class FileReaderDemo2 { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("demo.txt"); //定义一个字符数组。用于存储读到字符。 //该read(char[])返回的是读到字符个数。 <span style="color:#ff0000;"> char[] buf = new char[1024]; int num = 0; while((num=fr.read(buf))!=-1) { System.out.println(new String(buf,0,num)); } </span> fr.close(); } }
拷贝文件的练习
将C盘一个文本文件复制到D盘。
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。
步骤:
1,在D盘创建一个文件。用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据存储。
4,关闭资源。
注意:
定义文件路径时,可以用“/”或者“\\”。
在创建一个文件时,如果目录下有同名文 件将被覆盖。
在读取文件时,必须保证该文件已存在, 否则出异常。
import java.io.*; class CopyText { public static void main(String[] args) throws IOException { copy_2(); } public static void copy_2() { FileWriter fw = null; FileReader fr = null; try { fw = new FileWriter("SystemDemo_copy.txt");//将被写入的文件 fr = new FileReader("SystemDemo.java"); //将被读取的文件 char[] buf = new char[1024]; int len = 0; while((len=fr.read(buf))!=-1) { fw.write(buf,0,len); //一个数组一个数组的写入进去 } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { if(fr!=null) try { fr.close(); } catch (IOException e) { } if(fw!=null) try { fw.close(); } catch (IOException e) { } } } //从C盘读一个字符,就往D盘写一个字符。 public static void copy_1()throws IOException { //创建目的地。 FileWriter fw = new FileWriter("RuntimeDemo_copy.txt"); //与已有文件关联。 FileReader fr = new FileReader("RuntimeDemo.java"); int ch = 0; while((ch=fr.read())!=-1) { fw.write(ch); } fw.close(); fr.close(); } }
字符流的缓冲区
缓冲区的出现提高了对数据的读写效率。
对应类
• BufferedWriter
• BufferedReader
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强。
缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。
该缓冲区中提供了一个跨平台的换行符。
newLine();
import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { //创建一个字符写入流对象。 FileWriter fw = new FileWriter("buf.txt"); //为了提高字符写入流效率。加入了缓冲技术。 //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。 BufferedWriter bufw = new BufferedWriter(fw); for(int x=1; x<5; x++) { bufw.write("abcd"+x); bufw.newLine(); bufw.flush(); } //记住,只要用到缓冲区,就要记得刷新。 //bufw.flush(); //其实关闭缓冲区,就是在关闭缓冲区中的流对象。 bufw.close(); } }
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
import java.io.*; class BufferedReaderDemo { public static void main(String[] args) throws IOException { //创建一个读取流对象和文件相关联。 FileReader fr = new FileReader("buf.txt"); //为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。 BufferedReader bufr = new BufferedReader(fr); String line = null; while((line=bufr.readLine())!=null) { System.out.print(line); } bufr.close(); } }
/* 通过缓冲区复制一个.java文件。 */ import java.io.*; class CopyTextByBuf { public static void main(String[] args) { BufferedReader bufr = null; BufferedWriter bufw = null; try { bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java")); bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt")); String line = null; while((line=bufr.readLine())!=null) { bufw.write(line); bufw.newLine(); bufw.flush(); } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { try { if(bufr!=null) bufr.close(); } catch (IOException e) { throw new RuntimeException("读取关闭失败"); } try { if(bufw!=null) bufw.close(); } catch (IOException e) { throw new RuntimeException("写入关闭失败"); } } } }
装饰设计模式
对原有类进行了功能的改变,增强。 装饰模式的基本格式。
它与继承有什么不同? 了解BufferedReader的原理。
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
class MyBufferReader
{
MyBufferReader(MyTextReader text)
{}
MyBufferReader(MyMediaReader media)
{}
}
上面这个类扩展性很差。
找到其参数的共同类型。通过多态的形式。可以提高扩展性。
class MyBufferReader extends MyReader
{
private MyReader r;
MyBufferReader(MyReader r)
{}
}
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader
以前是通过继承将每一个子类都具备缓冲功能。那么继承体系会复杂,并不利于扩展。
现在优化思想。单独描述一下缓冲内容。将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。这样继承体系就变得很简单。优化了体系结构。
装饰模式比继承要灵活。避免了继承体系臃肿。而且降低了类于类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的。