重新深入的学习了IO流,将之前没搞懂的地方搞懂,这一篇旨在帮助大家理清IO流初始的结构体系。
- 什么是流。
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称和抽象。即数据在两个设备间的传输成为流,其本质就是数据传输。在根据数据传输特性将流抽象为各种类。
2.流的分类。
根据处理数据类型的不同:字符流(其实就是字节流加编码表)和字节流。 字节流和字符流的区别:
- 读写单位不同:字节流以字节为单位,字符流以字符为单位,根据码表映射字符,一次读取多个字节
- 处理对象的不同:字节流能处理所有类型的数据(图片,Mp3,avi等),而字符流只能处理字符类型的数据。
- 字节流的操作本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流的操作会用到缓冲区。
根据数据流向的不同:输入流和输出流。无码首先要明确的一点,输入和输出是对谁而言的?就是相对程序而言,也可以理解为内存,就是内存从外部(硬盘)读取数据。而输出就是,内存向硬盘中写入数据。
3.字节流
从输入字节流的继承图可以看出:InputStream 是所有的输入字节流的父类,它是一个抽象类。
ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。
PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。
ObjectInputStream 和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。意思是FileInputStream类可以通过一个String路径名创建一个对象,FileInputStream(String name)。
DataInputStream必须装饰一个类才能返回一个对象,DataInputStream(InputStream in)。
- inputstream
private static void demoread()throws IOException {
// TODO Auto-generated method stub
InputStream fis=new FileInputStream("wujie2.txt");
int ch=0;
while((ch=fis.read())!=-1){//read()方法,返回一个整数,若读取到流的末尾,返回-1;
System.out.println((char)ch);
}
}
IO 中输出字节流的继承图可见上图,可以看出:OutputStream 是所有的输出字节流的父类,它是一个抽象类。
ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。
PipedOutputStream 是向与其它线程共用的管道中写入数据,
ObjectOutputStream 和所有FilterOutputStream的子类都是装饰流。具体例子跟InputStream是对应的。
- outputstream
public static void main(String[] args) throws IOException{ OutputStream fos=new FileOutputStream("wujie2.txt"); fos.write("wujiedashuaib".getBytes());//字节流write操作的是字节,所以需要getbytes方法 demoread(); }
3.字符流常用操作。
reder:
在上面的继承关系图中可以看出:Reader 是所有的输入字符流的父类,它是一个抽象类。
CharReader、StringReader是两种基本的介质流,它们分别将Char 数组、String中读取数据。
PipedReader 是从与其它线程共用的管道中读取数据。
BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。
FileReader fwFileReader=new FileReader("wujie2.txt");
//取出的是二进制
char[] buf=new char[3];
int num=0;
while((num=fwFileReader.read(buf))!=-1){//read(char[])将字符读入数组/返回读取的字符数,若到达流末尾则返回-1
System.out.println(new String(buf));
}
fwFileReader.close();
Writer:
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//创建一个可以往文件中写入字符数据的输出流对象。
/*
* 既然是往一个文件中写入文字数据,那么在创建对象时,
* 就必须明确该文件(用于存储数据的目的地)
*
* 如果文件不存在,自动创建。
* 文件存在,被覆盖。
*
* 如果构造函数中加入true,可以实现对文件进行续写
*/
FileWriter fwFileWriter=new FileWriter("wujie.txt",true);
/*
* 调用writer对象中的write(string)方法,写入数据。
*
* 其实数据写入到临时缓冲区中
*/
fwFileWriter.write("wujie");
//刷新,将数据直接写入目标
//fwFileWriter.flush();
//关闭流,关闭前先刷新数据。
fwFileWriter.close();
}
- buffereredwriter/bufferedreader.缓冲流,提高效率(也就是一个装饰器类,另写。)
public static void main(String[] args) throws IOException {
FileWriter fwFileWriter=new FileWriter("wujie.txt",true);
BufferedWriter bfw =new BufferedWriter(fwFileWriter); //创建缓冲流,只要将字符流传参给它。
String str="wujiedadada"; bfw.write(str); //写操作 bfw.close(); //关闭缓冲流 out.close(); //关闭流}
转换流:InputStreamReader/OutPutStreamWriter
转换流的特点:
(1)其是字符流和字节流之间的桥梁
(2)可对读取到的字节数据经过指定编码转换成字符
(3)可对读取到的字符数据经过指定编码转换成字节
何时使用转换流?
当字节和字符之间有转换动作时;
流操作的数据需要编码或解码时,如果操作文本文件需要明确具体的编码解码。FileWriter和Filereader就不行了,因为他们用的是默认的编码表。
public static void writeText_3() throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("u8_1.txt"),"UTF-8");//使用utf8编码表写入
osw.write("你好");
osw.close();
}
public static void readText_2() throws IOException, FileNotFoundException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("u8_1.txt"),"utf-8");//指定utf-8来读取文件,如果使用默认的FileReader,出来的是乱码
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
当需要使用缓冲流的时候;
public static void main(String[] args) throws IOException {
/*
* 1,需求:将键盘录入的数据写入到一个文件中。
*
* 2,需求:将一个文本文件内容显示在控制台上。
*
* 3,需求:将一个文件文件中的内容复制到的另一个文件中。
*/
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}