-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
一、理解IO流
IO流是对 Input Output流的简称。
Java中对数据的操作是通过流来操作的,IO流是用来处理设备之间的数据传输。Java中用于操作流的对象都在IO包中。
流的分类:
按照流向分:输入流和输出流。
按照操作的数据分:字节流和字符流。
字符流的由来:
既然IO流是用于操作数据的,那么数据的最常见的体现形式是:文件。那么字节流读取文字字节数据后,不直接操作而是先去查指定的编码表,获取相应的文字,再对这些文字进行操作。简单的说就是:字节流+编码表
二、IO常用基类
字节流的抽象基类:
InputStream 和 OutputStream
字符流的抽象基类:
Reader 和 Writer
1.字符流之FileWriter类
专门用于操作文件的子类对象。后缀名是其父类名,前缀名是其功能。该流对象一被初始化必须要有文件对象。
步骤:(1)创建一个FileWriter对象,并初始化。初始化的该文件会被创建到指定目录下。如果该目录下有同名文件,则覆盖。
(2)调用 write( ) 方法,将字符串写入流中。
(3)通过 flush( ) 方法,刷新流对象中的缓存中的数据,将数据刷到指定文件中。
(4)关闭流资源, close( ) 方法,关闭前会刷新流对象。
flush 和 close 的区别:flush 刷新后可以继续使用流资源, close 刷新后流资源被关闭,不能继续使用。
2.IO流异常处理
(1)必须在方法一开始就建立外部引用,然后再try中对其初始化。
(2)初始化 write 方法和close 方法都会抛出异常,都要try
(3)在close方法调用时,必须先判断对象是否为空,也就是判断对象是否初始化成功。而且close方法一定要写在finally中,是必须执行的。
代码示例
import java.io.*; class FileWriterDemo { public static void main(String[] args) { FileWriter fw = null; //外部建立引用 try { fw = new FileWriter("java01.txt"); //将其初始化 String s = "abcdefg"; fw.write(s); //将字符串写入 fw.flush(); //将流内数据刷入文件 } catch (IOException e) { System.out.println("文件创建失败"); } finally { try { if(fw!=null)//对文件是否创建成功进行判断 fw.close();// close会抛异常,必须单独try } catch (IOException ie) { System.out.println("关闭资源失败"); } } } }
运行结果
3.对已有文件的数据续写
已有文件是指,原本在硬盘中就有的文件,我们为了保留其原始数据
(1)建立数据存放的目的地,但构造函数是其另一个重载形式。
例:FileWriter fw = new FileWriter("java01.txt",true); 这里的Java01.txt 是已有文件的文件名,true 代表这在文件末尾续写。
(2)调用write 方法
(3)调用close方法
4.字符流之FileReader类
(1)创建一个文件读取流对象,并和指定名称的文件相关联。必须保证该文件存在,如果不存在会发生FileNotFoundException异常。
(2)调用读取流read( ) 方法。该方法的返回值时int 型的。
read方法一次读一个字符,而且会自动往下读,读到末尾返回 -1 。
read 方法有两种使用方式:
FileReader fr = new FileReader("java01.txt");
第一种方法:
int ch = 0;
while((ch=fr.read())!=-1) {
System.out.print((char)ch);
}
第二中方式:
通过字符数组进行读取。定义一个字符数组,用于存储读到的数据。该read(char [ ] ) 方法返回的是读到字符的个数。如果到达末尾则返回 -1
char[ ] ch = new char[1024]; // 通常将长度定义为1024的整数倍
int num = 0; //定义一个变量用来存储 read方法返回的字符个数
while((num = fr.read(ch))!=-1) { // 其中fr.read(ch); 这句话就是将读到的字符装到数组里面,如果到达末尾就返回 -1
System.out.println(new String(ch,0,num)); // String对象构造函数,可以将数组转成字符串。
}
read 及 close 方法同样也会抛异常,所以也必须要try
三、字符流的缓冲区
1.为什么会出现字符流缓冲区
字符流缓冲区技术,是为了提高对数据读写的效率,所以在创建缓冲区钱必须现有流对象。缓冲区必须要结合流才能使用,在流的基础上对流的功能进行增强。
2.缓冲区有哪些?
缓冲区对应的类有两个:BufferedReader 和 BufferedWriter
3.缓冲区使用的步骤
BufferedWriter步骤:
(1)创建写入流对象
(2)创建缓冲区,并将流对象作为参数传递给缓冲区构造函数。(缓冲区没有空参构造函数)
(3)刷新
(4)关闭缓冲区,其实关闭缓冲区就是关闭流对象。
BufferedWriter 中:newline() 方法,写入一个行分隔符,具有跨平台性。
BufferedReader步骤:
(1)创建一个读取流对象,并和文件相关联。
(2)为了提高效率加入缓冲区技术,将字符读取流对象作为参数,传递给缓冲区构造函数。
(3)关闭缓冲区
BufferedReader 中:readLine( ) 一次读一行文本,是高效方法。该方法返回值类型是String ,当读完时返回null
四、装饰设计模式
当想要对已有的对象进行功能增强时,可以定义一个类,将已有的对象传入构造函数,基于已有对象的功能,并提供增强功能。那么自定义的该类就称为装饰类。
装饰类通常会通过构造函数接收被装饰的对象,并基于被装饰对象的功能,提供增强功能。
装饰和继承的区别:
装饰模式比继承更灵活,为了避免继承体系的臃肿,而且还降低类与类之间的关系,提高了扩展性。
装饰类因为增强已有对象,具备的功能和被装饰的类是相同的,只不过提供了更强的功能。所有装饰类和被装饰类通常都属于一个体系中。
五、字节流
字节流有两个基类:InputStream 读 和 OutputStream 写
当我们不操作文本文件的时候,就要用到字节流来实施操作。
字节流不需要刷新,但仍需要close
注意:字节流操作的是字节数组。不管你想写入字符串还是其他,都必须将其转换为字节数组,然后在用write方法写入。字节流的读写操作与字符流类似,但所操作的对象必须是byte类型。复制媒体文件一定要用字节流。
available() 方法:返回了字节数组的长度,类型为int 。
字节流缓冲区:
BufferedInputStream 和 BufferedOutputStream
字节流缓冲区用法和字符流缓冲区差不多
六、转换流
键盘录入:System.in
转换流两个:InpuerStreamReader 和 OutputStreamWriter
流操作的基本规律:只要明确源和目的,就可以方便的操作流对象
(1)明确源和目的地。源:输入流 ;目的:输出流
(2)明确操作的数据是不是纯文本?是:字符流 ;不是:字节流
(3)当明确体系后,在明确要使用哪个具体对象,通过设备来区分。源设备:键盘、内存、硬盘 ; 目的设备:控制台、内存、硬盘
(4)要不要使用缓冲区,一般都使用。
例:需求:将键盘录入的数据存到一个文本文件中
源:InputStream Reader
是不是纯文本?是,选Reader
设备:键盘,System.in 因为是Reader ,所有用到转换流
需要提高效率吗?要!
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
设备:OutputSteam Writer
是不是纯文本?是,选Writer
设备:硬盘,直接使用FileWriter
要不要提高效率?要!
BufferedWriter bufw = new BufferedWriter(new FileWriter("demo.txt"));
扩展:想要录入的数据按照指定的编码表,将数据存到文件中,由于FileWriter是使用系统默认码表,这时,要按照指定码表,就必须用到转换流。
那么代码变成:BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("demo.txt"),"UTF-8"));
记住:转换流是字符和字节之间的桥梁,通常涉及到字节、字符的转换时使用。