——- android培训、java培训、期待与您交流! ———-
黑马程序员——IO流
- IO流用来处理设备之间的数据传输
- Java对数据的操作是通过流的方式
- Java用于操作流的对象都在IO包中
- 流按操作数据分为两种:字节流与字符流。
- 流按流向分为:输入流,输出流。
IO流常用基类
- 字节流的抽象基类:
- InputStream, OutputStream。
- 字符流的抽象基类:
- Reader, Writer。
- 注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
- 如:InputStream的子类FileInputStream。
- 如:Reader的子类FileReader。
字符流
字符流:为了处理文字数据方便而出现的对象。
其实这些对象的内部使用的还是字节流(因为文字最终也是字节数据)
只不过,通过字节流读取了相对应的字节数,没有对这些字节直接操作。
而是去查了指定的(本机默认的)编码表,获取到了对应的文字。
简单说:字符流就是 : 字节流+编码表。
字符流——创建文件
- 创建流对象,建立数据存放文件
FileWriter fw = new FileWriter("Test.txt");
- 调用流对象的写入方法,将数据写入流
fw.write("text");
- 关闭流资源,并将流中的数据清空到文件中。
fw.close();
代码:
FileWriter fw = null;
try {
fw = new FileWriter("Test.txt");
fw.write("text");
} catch (IOException e) {
System.out.println(e.toString());
} finally {
if (fw != null) {
try{
fw.close();
} catch (IOException e) {
System.out.println(e.toString());
}
}
}
字符流——读取文件
- 建立一个流对象,将已存在的一个文件加载进流。
FileReader fr = new FileReader("Test.txt");
- 创建一个临时存放数据的数组。
char[] ch = new char[1024];
- 调用流对象的读取方法将流中的数据读入到数组中。
fr.read(ch);
代码:
FileReader fr = null;
try {
fr = new FileReader("c:\\test.txt");
char[] buf = new char[1024];
int len = 0;
while ((len = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
} catch (IOException e) {
System.out.println("read-Exception :" + e.toString());
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
System.out.println("close-Exception :" + e.toString());
}
}
}
字符流继承体系简图
字符流的缓冲区
- 缓冲区的出现提高了对数据的读写效率。
- 缓冲技术原理:此对象中封装了数组,将数据存入,再一次性取出。
- 对应类
- BufferedWriter
- BufferedReader
- 缓冲区要结合流才可以使用。
- 在流的基础上对流的功能进行了增强。
装饰设计模式
- 简述
- 当想对已有对象进行功能增强时,可定义类:将已有对象传入,基于已有对象的功能,并提供加强功能,那么自定义的该类称之为装饰类。
- 特点
- 装饰类通常都会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
- 装饰和继承的区别:
- 装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。
- 装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。
- 从继承结构转为组合结构。
注:在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。
- BufferedReader的原理。
- 使用流的read方法从源中读取一批数据存储到缓冲区的数组中。
- 通过计数器记录住存储的元素个数。
- 通过数组的角标来获取数组中的元素(从缓冲区中取数据).
- 指针会不断的自增,当增到数组长度,会归0.计数器会自减,当减到0时,就在从源拿一批数据进缓冲区。
自定义BufferedReader:
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
/**
* 自定义的读取缓冲区。其实就是模拟一个BufferedReader.
*
* 分析: 缓冲区中无非就是封装了一个数组, 并对外提供了更多的方法对数组进行访问。 其实这些方法最终操作的都是数组的角标。
*
* 缓冲的原理: 其实就是从源中获取一批数据装进缓冲区中。 在从缓冲区中不断的取出一个一个数据。
*
* 在此次取完后,在从源中继续取一批数据进缓冲区。 当源中的数据取光时,用-1作为结束标记。
*
*
* @author Administrator
*
*/
public class MyBufferedReader extends Reader {
private Reader r;
// 定义一个数组作为缓冲区。
private char[] buf = new char[1024];
// 定义一个指针用于操作这个数组中的元素。当操作到最后一个元素后,指针应该归零。
private int pos = 0;
// 定义一个计数器用于记录缓冲区中的数据个数。 当该数据减到0,就从源中继续获取数据到缓冲区中。
private int count = 0;
MyBufferedReader(Reader r) {
this.r = r;
}
/**
* 该方法从缓冲区中一次取一个字符。
*
* @return
* @throws IOException
*/
public int myRead() throws IOException {
// 从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。
if (count == 0) {
count = r.read(buf);
pos = 0; // 每次获取数据到缓冲区后,角标归零.
}
if (count < 0)
return -1; // 代表流读完了
char ch = buf[pos++];
count--;
return ch;
}
public String myReadLine() throws IOException {
StringBuilder sb = new StringBuilder();
int ch = 0;
while ((ch = myRead()) != -1) {
if (ch == '\r')
continue;
if (ch == '\n')
return sb.toString();
// 将从缓冲区中读到的字符,存储到缓存行数据的缓冲区中。
sb.append((char) ch);
}
if (sb.length() != 0)
return sb.toString();
return null;
}
public void myClose() throws IOException {
r.close();
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return 0;
}
@Override
public void close() throws IOException {
}
}
字节流
- 基本操作与字符流类相同
- 但它不仅可以操作字符,还可以操作其他媒体文件
字节流继承体系简图
字符流的缓冲区
- 同样是提高了字节流的读写效率。
- 读写特点:
- read():会将字节byte型值提升为int型值
- write():会将int型强转为byte型,即保留二进制数的最后八位。
转换流
- InputStreamReader, OutputStreamWriter
- 转换流的由来
- 字符流与字节流之间的桥梁
- 方便了字符流与字节流之间的操作
- 转换流的应用
- 字节流中的数据都是字符时,转成字符流操作更高效。
标准输入输出流
- System类中的字段:in,out。
- 它们各代表了系统标准的输入和输出设备。
- 默认输入设备是键盘,输出设备是显示器。
- System.in的类型是InputStream.
- System.out的类型是PrintStream是OutputStream的子类FilterOutputStream的子类.
示例
- InputStreamReader将字节流通向字符流
- 获取键盘录入对象。
InputStream in=System.in;
- 将字节流对象转成字符流对象,使用转换流。
InputStreamReaderisr=new InputStreamReader(in);
- 为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
BufferedReaderbr=new BufferedReader(isr);
- //键盘录入最常见写法
BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
- 获取键盘录入对象。
- OutputStreamWriter字符流通向字节流
- 字符通向字节:录入的是字符,存到硬盘上的是字节。步骤和InputStreamReader转换流一样。
/*
需求:将键盘录入的数据,显示在控制台,当输入over时,表示结束
源:键盘录入。
目的:控制台。
*/
import java.io.*;
class TransStreamDemo {
public static void main(String[] args) throws IOException {
// 获取键盘录入对象。
// InputStream in=System.in;
// 将字节流对象转成字符流对象,使用转换流。
// InputStreamReader isr=new InputStreamReader(in);
// 为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
// BufferedReader br=new BufferedReader(isr);
// 键盘录入最常见写法
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
// 字符流通向字节流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
System.out));
String s = null;
while ((s = in.readLine()) != null) {
if ("over".equals(s))
break;
bw.write(s.toUpperCase());// 写入数据
bw.newLine();// 换行
bw.flush();// 刷新
}
bw.close();// 关闭流资源
in.close();
}
}
IO流的操作规律总结
- 明确体系:
- 数据源:InputStream ,Reader
- 数据汇:OutputStream,Writer
- 明确数据:因为数据分两种:字节,字符。
- 数据源:是否是纯文本数据呢?
- 是:Reader
- 否:InputStream
- 数据汇:
- 是:Writer
- 否:OutputStream
- 数据源:是否是纯文本数据呢?
- 明确设备:
- 数据源:
- 键盘:System.in
- 硬盘:FileXXX
- 内存:数组。
- 网络:socket socket.getInputStream();
- 数据汇:
- 控制台:System.out
- 硬盘:FileXXX
- 内存:数组
- 网络:socket socket.getOutputStream();
- 数据源:
- 明确额外功能:
- 需要转换?是,使用转换流。InputStreamReader OutputStreamWriter
- 需要高效?是,使用缓冲区。Buffered
- 需要其他?
示例:
- 复制一个文本文件。
- 明确体系:
- 源:InputStream ,Reader
- 目的:OutputStream ,Writer
- 明确数据:
- 源:是纯文本吗?是 Reader
- 目的;是纯文本吗?是 Writer
- 明确设备:
- 源:硬盘上的一个文件。 FileReader
- 目的:硬盘上的一个文件。FileWriter
- FileReader fr = new FileReader(“a.txt”);
- FileWriter fw = new FileWriter(“b.txt”);
- 需要额外功能吗?
- 需要,高效,使用buffer
- BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
- BufferedWriter bufw = new BufferedWriter(new FileWriter(“b.txt”));
- 明确体系:
- 读取键盘录入,将数据存储到一个文件中。
- 明确体系:
- 源:InputStream ,Reader
- 目的:OutputStream ,Writer
- 明确数据:
- 源:是纯文本吗?是 Reader
- 目的;是纯文本吗?是 Writer
- 明确设备:
- 源:键盘,System.in
- 目的:硬盘,FileWriter
- InputStream in = System.in;
- FileWriter fw = new FileWriter(“a.txt”);
- 需要额外功能吗?
- 需要,因为源明确的体系时Reader。可是源的设备是System.in。
- 所以为了方便于操作文本数据,将源转成字符流。需要转换流。InputStreamReader
- InputStreamReader isr = new InputStreamReader(System.in);
- FileWriter fw = new FileWriter(“a.txt”);
- 需要高效不?需要。Buffer
- BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
- BufferedWriter bufw = new BufferedWriter(new FileWriter(“a.txt”));
- 明确体系:
- 读取一个文本文件,将数据展现在控制台上。
- 明确体系:
- 源:InputStream ,Reader
- 目的:OutputStream ,Writer
- 明确数据:
- 源:是纯文本吗?是 Reader
- 目的;是纯文本吗?是 Writer
- 明确设备:
- 源:硬盘文件,FileReader。
- 目的:控制台:System.out。
- FileReader fr = new FileReader(“a.txt”);
- OutputStream out = System.out;
- 需要额外功能?
- 因为源是文本数据,确定是Writer体系。所以为了方便操作字符数据,
- 需要使用字符流,但是目的又是一个字节输出流。
- 需要一个转换流,OutputStreamWriter
- FileReader fr = new FileReader(“a.txt”);
- OutputStreamWriter osw = new OutputStreamWriter(System.out);
- 需要高效吗?需要。
- BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
- 明确体系:
- 读取键盘录入,将数据展现在控制台上。
- 明确体系:
- 源:InputStream ,Reader
- 目的:OutputStream ,Writer
- 明确数据:
- 源:是纯文本吗?是 Reader
- 目的;是纯文本吗?是 Writer
- 明确设备:
- 源:键盘:System.in
- 目的:控制台:System.out
- InputStream in = System.in;
- OutputStream out = System.out;
- 需要额外功能吗?
- 因为处理的数据是文本数据,同时确定是字符流体系。
- 为方便操作字符数据的可以将源和目的都转成字符流。使用转换流。
- 为了提高效率,使用Buffer
- BufferedReader bufr =new BufferedReader(new InputStreamReader(Systme.in));
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
- 明确体系:
- 读取一个文本文件,将文件按照指定的编码表UTF-8进行存储,保存到另一个文件中。
- 明确体系:
- 源:InputStream ,Reader
- 目的:OutputStream ,Writer
- 明确数据:
- 源:是纯文本吗?是 Reader
- 目的;是纯文本吗?是 Writer
- 明确设备:
- 源:硬盘:FileReader.
- 目的:硬盘:FileWriter
- FileReader fr = new FileReader(“a.txt”);
- FileWriter fw = new FileWriter(“b.txt”);
- 额外功能:
- 注意:目的中虽然是一个文件,但是需要指定编码表。
- 而直接操作文本文件的FileWriter本身内置的是本地默认码表。无法明确具体指定码表。
- 这时就需要转换功能。OutputStreamWriter,而这个转换流需要接受一个字节输出流,而且
- 对应的目的是一个文件。这时就使用字节输出流中的操作文件的流对象。FileOutputStream.
- FileReader fr = new FileReader(“a.txt”);
- OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“b.txt”),”UTF-8”);
- 需要高效吗?
- BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“b.txt”),”UTF-8”));
- 明确体系:
IO包中的其他类
- RandomAccessFile
- 随机访问文件,自身具备读写的方法。
- 通过skipBytes(int x),seek(int x)来达到随机访问。
- 管道流
- PipedInputStream和PipedOutputStream
- 输入输出可以直接进行连接,通过结合线程使用。
- PipedInputStream和PipedOutputStream
- 打印流
- PrintWriter与PrintStream
- 可以直接操作输入流和文件。
- PrintWriter与PrintStream
- 序列流
- SequenceInputStream
- 对多个流进行合并。
- SequenceInputStream
- 操作对象
- ObjectInputStream与ObjectOutputStream
- 被操作的对象需要实现Serializable (标记接口);
- ObjectInputStream与ObjectOutputStream
- 操作基本数据类型
- DataInputStream与DataOutputStream
- 操作字节数组
- ByteArrayInputStream与ByteArrayOutputStream
- 操作字符数组
- CharArrayReader与CharArrayWrite
- 操作字符串
- StringReader 与 StringWriter
IO流体系
字符流:
Reader
|--BufferedReader
|--LineNumberReader
|--CharArrayReader
|--StringReader
|--InputStreamReaer
|--FileReader
Writer
|--BufferedWriter
|--CharArrayWriter
|--StringWriter
|--OutputStreamWriter
|--FileWriter
|--PrintWriter
字节流:
InputStream
|--FileInputStream
|--FilterInputStream
|--BufferedInputStream
|--DataInputStream
|--ByteArrayInputStream
|--ObjectInputStream
|--SequenceInputStream
|--PipedInputStream
OutputStream
|--FileOutputStream
|--FilterOutputStream
|--BufferedOutputStream
|--DataOutputStream
|--ByteArrayOutputStream
|--ObjectOutputStream
|--PipedOutputStream
|--PrintStream
RandomAccessFile