IO流
大多数应用程序都需要实现与设备之间的传输,例如键盘可以输入数据,显示器可以显示程序的运行结果等。在JAVA中,将这种通过不同输入输出设备之间数据传输抽象表述为“流”,程序允许通过流的方式与输入输出设备进行数据传输。在java中“流”都位于java.io包中,成为IO(输入输出)流。
IO流有很多中,按照操作数据的不同,可以分为字节流和字符流,按照数据传输方向不同又可分为输入流和输出流,程序从输入流中读取数据,向输出流中写入数据。在IO包中,字节流的输入输出分别用java.io.InputStream和java.io.OutputStream表示,字符流的输入输出流分别用java.io.Reader和java.io.Writer表示。
输出流即是从代码向固定目标写入数据,输入流即从内存中拿取字节到代码。
一、字节流
在计算机中,无论是文本、图片、音频还是视频,所有文件都是以二进制(字节)形式存在的,IO流中正对字节的输入输出提供了一系列的流,统称字节流。字节流是程序中最常见的流,根据数据的传输方向可以将其分为字节输入流和字节输出流。在JDK中,提供了两个抽象类InputSteam和OutputStream,它们是字节流的顶级父类,所有的字节输入流都继承自InputStream,所有的字节输出流都继承自OutputStream。
在JDK中,InputStream和OutputStream提供了一系列读与写数据相关的方法。下表是InputStream的常用方法。
方法声明 | 功能描述 |
---|---|
int read | 从输入流读取数据的下一个字节。 |
int read(byte[] b) | 从输入流读取一些字节数,并将它们存储到缓冲区 b 。 |
int read(byte[] b, int off, int len) | 从输入流读取最多 len 字节的数据到一个字节数组。 |
void close() | 关闭此输入流并释放与流相关联的任何系统资源。 |
表中列举了InputStream的四个常用的方法,前三个read()方法都是用来读数据的,其中,第一个read()方法是从输入了流中逐个读入字节,而第二个和第三个read()方法则将若干以字节数组的形式一次性读入,从而提高读数据的效率。在进行IO流操作时,当前IO流会占用一定的内存,由于系统资源宝贵,因此,在IO操作结束后,应调用close()方法关闭流,从而释放当前IO流所占的系统资源。
与InputStream对应的是Outputtream。OutputStream是用于写数据的,因此OutputStream提供了一些与写数据有关的方法,如下表:
方法声明 | 方法描述 |
---|---|
void write(int b) | 将指定的字节写入此输出流 |
void write(byte[] b) | 将 b.length 字节从指定的字节数组写入此输出流。 |
void write(byte[] b, int off, int len) | 从指定的字节数组写入 len 个字节,从偏移 off 开始输出到此输出流。 |
void flush() | 刷新此输出流并强制任何缓冲的输出字节被写出。 |
void close() | 关闭此输出流并释放与此流相关联的任何系统资源。 |
表中列举了OutputStream类的五个常用方法。前面三个是重载的write()方法,都是用于向输出流写入字节,其中,第一个方法逐个写入字节,后两个方法是将若干个字节以字节数组的形式一次性写入,从而提高写数据的效率。flush()方法用来将当前输出流缓冲区(通常是字节数组)中的数据强制写入目标设备,此过程成为刷新。close()方法是用来关闭流并释放与当前IO流相关的系统资源。
InputStream和OutputStream这两个类虽然提供了一系列和读写数据有关的方法,但是这连个类是抽象类,不能被实例化,因此,针对不同的功能,inputStream和outputstream提供了不同的子类,这些子类形成一个体系结构。
1.字节流读写文件
由于计算机中的数据基本都保存在硬盘的文件中,因此操作文件中的数据是一种很常见的操作。在操作文件时,最常见的就是从文件中读取数据并将数据写入文件,即文件的读写。正对文件的读写,JDK专门提供了两个类,分别是FileInputStream和FileOutputStream。
FileInputStream是InputStream的子类,它是操作文件的字节输入流,专门用于读取文件中的数据。由于从文件读取数据是重复的操作,因此需要通过循环语句来实现数据的持续读取。
import java.io.FileInputStream;
public class Example01 {
/**
* 字节流对文件数据的读取
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//创建一个文件字节输入流
FileInputStream in = new FileInputStream("test.txt");
//定义一个int类型的变量b,记住每次读取的一个字节
int b = 0;
while(true) {
b = in.read();//变量b记住读的每个字节
if (b == -1) {
//如果读取的字节为-1,说明读取完毕
break;//跳出循环
}
System.out.println(b);
}
//关闭,释放系统资源
in.close();
}
}
FileOutputStream是OutputStream的子类,它是操作文件的字节输出流,专门用于把数据写入文件。
import java.io.FileOutputStream;
/*
* 使用FileOutPutStream将文件写入文件
*/
public class example02 {
public static void main(String[] args) throws Exception {
//创建一个文件字节输入流
FileOutputStream out = new FileOutputStream("example02.txt");
String str = "summer";
byte[] b = str.getBytes();//将字符串变成字节
for (int i = 0; i < b.length; i++) {
out.write(b[i]);
}
out.close();
}
}
直接使用write是进行覆盖写入,接下来的代码是以追加方式写入数据。
import java.io.FileOutputStream;
import java.io.OutputStream;
public class example03 {
/*
*使用FileOutputStream将数据以追加的形式写道文件的末尾
*/
public static void main(String[] args) throws Exception {
//创建一个文件字节输出流
OutputStream out = new FileOutputStream("example02.txt",true);
String str = "欢迎你";
byte[] b = str.getBytes();
for (int i = 0; i < b.length; i++) {
out.wait(b[i]);
}
out.close();
}
}
由于IO流在进行数据读写操作时会出现异常,为了代码的简介,在上面的程序中使用了throws关键字将异常抛出,然而一旦遇到IO异常,IO流的close方法将无法得到执行,流对象所占用的资源将得不到释放,因此,为了保证IO流的close方法必须执行,通常将关闭流的操作写在finally代码块中。
2.文件的拷贝
在应用程序中,IO流通常是成对出现的,即输入流和输出流一起使用。例如文件的拷贝就需要通过输入流和输出流来读取文件中的数据,通过输出流将数据写入文件。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;