——- android培训、java培训、期待与您交流! ———-
概述
流用于处理设备上数据。
流:可以理解数据的流动,就是一个数据流。IO流最终要以对象来体现,对象都存在IO包中。
流也进行分类:
1:按照数据流的方向不同可以分为:输入流和输出流。
2:按照处理数据单位不同可以分为:字节流和字符流。
3:按照实现功能不同可以分为:节点流和处理流。
具体请看 上一个blog《Java IO流<总览>》
补充
IO中的使用到的设计模式:装饰设计模式。
装饰设计模式解决:对一组类进行功能的增强。
包装:写一个类(包装类)对被包装对象进行包装;
* 1、包装类和被包装对象要实现同样的接口;
* 2、包装类要持有一个被包装对象;
* 3、包装类在实现接口时,大部分方法是靠调用被包装对象来实现的,对于需要修改的方法我们自己实现;
流的操作规律:
1,明确源和目的。
数据源:就是需要读取,可以使用两个体系:InputStream、Reader;
数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;
2,操作的数据是否是纯文本数据?
如果是:数据源:Reader
数据汇:Writer
如果不是:数据源:InputStream
数据汇:OutputStream
3,虽然确定了一个体系,但是该体系中有太多的对象,到底用哪个呢?
明确操作的数据设备。
数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)
数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。
4,需要在基本操作上附加其他功能吗?
比如缓冲。 如果需要就进行装饰。
转换流
转换流特有功能:
转换流可以将字节转成字符,原因在于,将获取到的字节通过查编码表获取到指定对应字符。
转换流的最强功能就是基于 字节流 + 编码表 。没有转换,没有字符流。
发现转换流有一个子类就是操作文件的字符流对象:
InputStreamReader
|–FileReader
OutputStreamWriter
|–FileWrier
想要操作文本文件,必须要进行编码转换,而编码转换动作转换流都完成了。所以操作文件的流对象只要继承自转换流就可以读取一个字符了。
但是子类有一个局限性,就是子类中使用的编码是固定的,是本机默认的编码表,对于简体中文版的系统默认码表是GBK。
PrintStream:打印流
1:提供了更多的功能,比如打印方法。可以直接打印任意类型的数据。
2:它有一个自动刷新机制,创建该对象,指定参数,对于指定方法可以自动刷新。
3:它使用的本机默认的字符编码.
4:该流的print方法不抛出IOException。
该对象的构造函数。
PrintStream(File file) :创建具有指定文件且不带自动行刷新的新打印流。
PrintStream(File file, String csn) :创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
PrintStream(OutputStream out) :创建新的打印流。
PrintStream(OutputStream out, boolean autoFlush) :创建新的打印流。
PrintStream(OutputStream out, boolean autoFlush, String encoding) :创建新的打印流。
PrintStream(String fileName) :创建具有指定文件名称且不带自动行刷新的新打印流。
PrintStream(String fileName, String csn)
PrintStream可以操作目的:
1:File对象。2:字符串路径。3:字节输出流。
前两个都JDK1.5版本才出现。而且在操作文本文件时,可指定字符编码了。
当目的是一个字节输出流时,如果使用的println方法,可以在printStream对象上加入一个true参数。这样对于println方法可以进行自动的刷新,而不是等待缓冲区满了再刷新。最终print方法都将具体的数据转成字符串,而且都对IO异常进行了内部处理。
既然操作的数据都转成了字符串,那么使用PrintWriter更好一些。因为PrintWrite是字符流的子类,可以直接操作字符数据,同时也可以指定具体的编码。
PrintWriter具备了PrintStream的特点同时,还有自身特点:
该对象的目的地有四个:1:File对象。2:字符串路径。3:字节输出流。4:字符输出流。
开发时尽量使用PrintWriter。
方法中直接操作文件的第二参数是编码表。
直接操作输出流的,第二参数是自动刷新。
//读取键盘录入将数据转成大写显示在控制台.
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//源:键盘输入
//目的:把数据写到文件中,还想自动刷新。
PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);//设置true后自动刷新
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
out.println(line.toUpperCase());//转大写输出
}
注意:System.in,System.out这两个标准的输入输出流,在jvm启动时已经存在了。随时可以使用。当jvm结束了,这两个流就结束了。但是,当使用了显示的close方法关闭时,这两个流在提前结束了。
out.close();
bufr.close();
应用:
package XianChen;
import java.io.*;
import java.util.*;
public class LiZi {
public static void main(String[] args) throws Exception {
fuzhi_1();
fuzhi_2();
fuzhi_3();
}
// FileReader()、FileWriter();
// 创建文本文件
public static void fuzhi_1() {
/*
1:创建一个字符输出流对象,用于操作文件。该对象一建立,就必须明确数据存储位置,是一个文件。
2:对象产生后,会在堆内存中有一个实体,同时也调用了系统底层资源,在指定的位置创建了一个存储数据的文件。
3:如果指定位置,出现了同名文件,文件会被覆盖。
4: 流操作因为涉及外界数据,需要处理各种异常
*/
// 创建一个字符输入流对象
FileReader fr=null;
// 创建一个字符输出流对象
FileWriter fw=null;
// 将字符串写入文本
try {
// 初始化
// 创建一个文件对象 打印是否存在同名文件
System.out.println(!(new File("yuan.txt").createNewFile()));
// 文件必须存在,否则报异常
fr = new FileReader("yuan.txt");
fw = new FileWriter("yuan.txt");
// 定义要存入文本的字符串
String str = "ABCDEF\r\n123456\r\n";
// 存入指定文本
fw.write(str);
// 读取刚才的文本
// 定义简单缓冲区
int num;
// 读取单个字符,如果已到达流的末尾,则返回 -1
while((num=fr.read())!=-1){
// 将文本内容打印到控制台
// 输出结果:
// ABCDEF
// 123456
System.out.print((char)num);
}
} catch (Exception e1) {
e1.printStackTrace();
// 最终动作关流
// 关闭流,其实关闭的就是java调用的系统底层资源。在关闭前,会先刷新该流。
// close()和flush()的区别:
// flush():将缓冲区的数据刷到目的地中后,流可以使用。
// close():将缓冲区的数据刷到目的地中后,流就关闭了,该方法主要用于结束调用的底层资源。这个动作一定做。
}finally{
// 流需要单独关,分别try
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// FileInputStream、FileOutputStream();
// 复制一个 图片
public static void fuzhi_2() {
// 创建一个字节输入流对象
FileInputStream fi = null;
// 创建一个字节输出流对象
FileOutputStream fo = null;
try {
String name_yu = "yuan.jpg";
String name_fu = "fuben.jpg";
fi = new FileInputStream(name_yu);
fo = new FileOutputStream(name_fu);
// 定义简单缓冲区
int num;
// 读取单个字符,如果已到达流的末尾,则返回 -1
while((num=fi.read())!=-1){
fo.write(num);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 录入键盘数据,并保存在文本文件中
public static void fuzhi_3() {
// 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读写。
BufferedReader br=null;
BufferedWriter bw=null;
//转换流
//是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
//它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
//每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。
//要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
InputStreamReader isr = null;
OutputStreamWriter osw= null;
// 字节输出流,输出到文件
FileOutputStream fos;
PrintWriter pr =null;
try{
// 建立键盘读取流
br = new BufferedReader(new InputStreamReader(System.in));
// ==> isr = new InputStreamReader(System.in);
// br = new BufferedReader(isr);
// 建立文件输出流 1
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("键盘录入.txt")));
// 建立文件输出流 2 (开发推荐)
pr = new PrintWriter("PrintDemo.txt");
// 定义简单缓冲变量
String line;
int num =0;
// 读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。
// readLine方法返回的时候是不带换行符的。
while((line=br.readLine())!=null){
// 判断输入终止,双空行
if(line.length()==0){
num++;
if(num==2)
break;
}else{
// 重置判断标志
num=0;
// 写入流中
bw.write(line);
// 打印流的特有方法、 自动换行
pr.println(line);
// 换行
bw.newLine();
// 刷新
bw.flush();
pr.flush();
}
}
}catch(IOException e){
System.out.println("wrong");
}
finally{
try {
if(br!=null)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(bw!=null)
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}