一、IO流
介绍IO流之前先介绍一下什么是IO,IO是input、output的简称,所以所谓的IO流也就是输入输出流,明白了这一点对后面的学习有很大的促进作用。
二、流的基类
我们按照操作对象的不同将流分为两大门派,一派是操作字符数据的我们称之为字符流,操作字节的一派我们称之为字节流。体系结构如下:
字符流:Reader、Writer
字节流:InputStream、OutputStream
字节流:处理字节数据的流对象。我们熟知的设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。也就是说,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。
字符流:在中文平台的计算机上存储数据的编码是GBK,国标是unicode所以在互相转化时就会出现乱码,因此需要在获取中文字节数据的同时指定编码表才可以正确的解析数据。为了方便操作,所以将字节流和编码封装成对象,这个对象就是字符流。
需要特别指出的是,上述四个类别两个门派作为基本有一个特点,就是其子类都是以父类的名字结尾,这样就极大的方便我们去掌握,比如InputStream的子类FileInputStream;Writer的子类FileWriter.
三、字符流
抽象基类:
|--Reader:字符输入流
|--Writer:字符输出流
四、FileWriter
FileWriter是Writer的一个子类(而且是OutputStreamWriter的子类),用来写入字符文件的便捷子类
构造方法:
|--FileWriter(File file)
根据给定的 File 对象构造一个 FileWriter 对象。
|--FileWriter(File file, boolean append)
根据给定的 File对象构造一个 FileWriter 对象。
|--FileWriter(FileDescriptor fd)
构造与某个文件描述符相关联的 FileWriter 对象。
|--FileWriter(String fileName)
根据给定的文件名构造一个 FileWriter 对象。
|--FileWriter(String fileName, boolean append)
根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。
可以实现文件的追加写入,第二个参数表示是否追加写入,默认是false,就会重头开始写入,如果是true,就会追加写入
常用方法:
|--void write(String str):写入字符串。
|--abstract void flush():刷新该流的缓冲
|--abstract void close():关闭此流,但要先刷新它。
应用示范
1、FileWriter的使用范例
新建文件,并在文件中写入字符
import java.io.FileWriter;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args) throws IOException {
//创建流对象,建立数据存放文件,指定目录和文件名
FileWriter f=new FileWriter("E:/aa.txt");
//调用FilterWriter的writer(String s)方法,向新建的文件中输出指定字符
f.write("我是 FileWriter创建的文件");
//刷新字符流中的数据,如果不刷新且不关闭流对象会出现空文件的现象
f.flush();
//关闭流对象,回收流资源,关闭流对象后流对象将无法使用,这与flush有着重大区别
f.close();
}
}
2、在已有的文件结尾添加字符,其实只需改动一处
FileWriter f=new FileWriter("E:/aa.txt",true);
其他部分内容相同
五、FileReader
FileReader是Reader的一个子类(是InputStreamReader的直接子类),用来读取字符文件的便捷类
构造方法:
|--FileReader(File file)
在给定从中读取数据的 File 的情况下创建一个新 FileReader。
|--FileReader(FileDescriptor fd)
在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。
|--FileReader(String fileName)
在给定从中读取数据的文件名的情况下创建一个新 FileReader。
两种读取方法:
|--int read():读取单个字符。
|--int read(char[] cbuf):将字符读入数组。
应用示范
1、 read()
import java.io.FileReader;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args) throws IOException {
//第一种方式read();
FileReader fr = new FileReader("E:/aa.txt");
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
int ch = 0;
while((ch = fr.read())!=-1){
System.out.print((char)ch);
}
fr.close();
}
}
第二中方式read(char[])
import java.io.FileReader;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args) throws IOException {
//第二种方式read(char[]);
FileReader fr = new FileReader("E:/aa.txt");
int i = 0;
char[] ch2 =newchar[1024];
while((i = fr.read(ch2))!=-1){
System.out.print(new String(ch2,0,i));
}
fr.close();
}
}
在上面介绍了基类Writer以及Reader的基本用法,不管是Writer还是Reader上面的用法有一个缺陷就是效率低,为了提高效率我们需要学习下面的内容——字符流缓冲区
六、字符流缓冲区
字符流缓冲区的出现就是为了提高对数据的读写效率,在流的基础上对功能进行增强,这里涉及一种设计模式——装饰设计模式,关于常见的设计模式在后面的文章中会有专题进行介绍这里不再详解。
常见缓冲区对应的类
BufferedWriter(? Extends Writer)
BufferedReader(? Extends Reader)
BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。该缓冲区中提供了一个跨平台的换行符:newLine();
本类方法(全部方法返回类型void):
|--close():关闭此流,但要先刷新它。
|--flush():刷新该流的缓冲。
|--newLine():写入一个行分隔符。 可跨平台使用
|--write(char[] cbuf, int off, int len):写入字符数组的某一部分。
|--write(int c):写入单个字符。
|--write(String s, int off, int len):写入字符串的某一部分。
使用示范
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args) throws IOException {
//创建一个字符写入流对象。
FileWriter fw = new FileWriter("E:/aa.txt");
//为了提高字符写入流效率。加入了缓冲技术。
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriter bufw = new BufferedWriter(fw);
for(int x=1; x<5; x++){
bufw.write("第"+x+"次写入");
bufw.newLine();
bufw.flush();//只要用到缓冲区,就要记得刷新。
}
//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();
}
}
七、BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
该缓冲区提供了一个一次读一行的方法 readLine(),方便于对文本数据的获取。当返回null时,表示读到文件末尾。(注:readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。)
常用方法:
|--void close():关闭该流并释放与之关联的所有资源。
|--int read():读取单个字符。
|--int read(char[] cbuf, int off, int len):将字符读入数组的某一部分。
|--String readLine():读取一个文本行。
使用范例
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args) throws IOException {
//创建一个读取流对象和文件相关联。
FileReader fr = new FileReader("E:/aa.txt");
//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);
String line =null;//定义一个用作临时存储数据的变量
while((line=bufr.readLine())!=null)//返回值不为null就一直循环
{
System.out.print(line);
}
bufr.close();
}
}
八、字节流
它的操作与字符流类似,可以参与字符流的定义、读取、写入、处理异常的格式,只不过是处理的数据不同,因为对于非字符的数据,比如图片、视频、音频文件(例如mp3)等,这些文件只能用字节流对之进行操作。
字节流的抽象基类:
|--InputStream:字节输入流
|--OutputStream:字节输出流
FileInputStream
FileInputStream是InputStream的一个子类,用于读取诸如图像数据之类的原始字节流
构造方法:
|--FileInputStream(File file)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
|--FileInputStream(FileDescriptor fdObj)
通过使用文件描述符 fdObj 创建一个 FileInputStream,该文件描述符表示到文件系统中某个实际文件的现有连接。
|--FileInputStream(String name)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
常用方法:
|--int available()返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
|--void close()关闭此文件输入流并释放与此流有关的所有系统资源。
|--int read()从此输入流中读取一个数据字节。
|--int read(byte[] b)从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
|--int read(byte[] b, int off, int len)从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
应用示范
import java.io.FileInputStream;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args) {
read1();
}
// 第一种读取方式:按字节来读取
public static void read1() {
FileInputStream fis =null;
try {
fis =new FileInputStream("E:/aa.java");//新建字节读取的对象,明确源文件
int x = 0;
while ((x = fis.read()) != -1) {
System.out.print((char) x);
}
} catch (IOException e) {
e.printStackTrace();
}finally {//执行关闭资源的操作
if (fis !=null) {
try {
fis.close();
}catch (IOException e2) {
e2.printStackTrace();
}
}
}
}
// 第二种读取方式:按字节数组读取
public static void read2() {
FileInputStream fis =null;
try {
fis =new FileInputStream("E:/aa.java");//新建字节读取的对象,明确源文件
int len = 0;
byte[] buff =new byte[1024];//定义一个字节数组,用于存储字节
while ((len = fis.read(buff)) != -1) {// 每次将读取到的字节存储进buff数组
System.out.println(new String(buff, 0, len));// 将字节数组转换成字符串输出
}
} catch (IOException e) {
e.printStackTrace();
}finally {// 执行关闭资源的操作
if (fis !=null) {
try {
fis.close();
}catch (IOException e2) {
e2.printStackTrace();
}
}
}
}
}
九、FileOutputStream
FileOutputStream是OutputStream的一个子类,用于写入诸如图像数据之类的原始字节的流。
构造方法:
|--FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
|--FileOutputStream(File file,boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
|--FileOutputStream(FileDescriptor desc)
创建一个向指定文件描述符处写入数据的输出文件流,该文件描述符表示一个到文件系统中的某个实际文件的现有连接。
|--FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流。
|--FileOutputStream(String name, boolean append)
创建一个向具有指定 name 的文件中写入数据的输出文件流。
常用方法:
|--close():关闭此文件输出流并释放与此流有关的所有系统资源。
|--write(byte[] b):将 b.length 个字节从指定byte数组写入此文件输出流中。
|--write(byte[] b, int off, int len):将指定byte数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
|--write(int b):将指定字节写入此文件输出流。
十、应用示范
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args){
FileOutputStream fos =null;
try{
fos =new FileOutputStream("E:/aa.txt");
//定义一个字符串,因为字节流只能以字节或字节数组的形式读取
String str ="天津这个鬼地方又出现了严重的雾霾";
byte [] by =str.getBytes();//转成字节数组形式
fos.write(by);//不用刷新
}
catch (Exception e) {
e.printStackTrace();
}
finally{
if(fos!=null){
try{
fos.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
十一、字节流缓冲区
字节流缓冲区同样是提高了字节流的读写效率。
对应类:
BufferedOutputStream (? extends OutputStream)
BufferedInputStream (? extends InputStream)
应用示范
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args){
BufferedInputStream buis=null;
BufferedOutputStream buos=null;
try{
//复制视频文件到指定目录
buis=new BufferedInputStream(new FileInputStream("E:\\分手大师.avi"));//使用匿名对象的方式建立字节流缓冲区对象
buos=new BufferedOutputStream(new FileOutputStream("F:\\copy_分手大师.avi"));
byte[] buff =new byte[1024*1024]; //定义一个1M的字节数组
int len = 0;
while((len=buis.read(buff))!=-1){
buos.write(buff,0,len);
}
}//关闭流资源
catch(IOException e) {
thrownew RuntimeException("复制失败");
}
finally{
if(buis!=null){
try {
buis.close();
}catch (Exception e2) {
thrownew RuntimeException("关闭读取流失败");
}
}
if(buos!=null){
try {
buos.close();
}catch (Exception e2) {
thrownew RuntimeException("关闭写入流失败");
}
}
}
}
}