流(stream):流是一组有序的数据序列,根据操作的类型,分为输入流和输出流两种。
输入流:输入流的指向称为源,程序从指向源的输入流中读取源中的数据。
输出流:输出流的指向是字节要去的目的地,程序通过向输出流中写入数据把信息传递到目的地。
流一般分为字节流、字符流两种。
1. InputStream & OutputStream
1.1 InputStream
InputStream类是字节输入流的抽象类,是所有字节输入流的父类。InputStream有多个子类,继承关系如下图所示,可以实现不同的数据输入流。
InputStream类常用方法如下表所示。
方法名称 | 功能描述 |
---|---|
int read() | 从输入流中读取单个字节,返回读取的字节数据(字节数据可直接转换为int类型) |
int read(byte[] b) | 从输入流中最多读取b.length个字节的数据,并存于字节数组b中,返回实际读取的字节数 |
int read(byte[] b, int off, int len) | 从输入流中最多读取len个字节的数据,并存于字节数组b中,放入数组b中时,从off位置开始存放,返回实际读取的字节数 |
close() | 关闭当前输入流,并释放任何与之关联的系统资源 |
1.2 OutputStream
OutputStream类是字节输出流的抽象类,是所有字节输出流的父类。OutputStream有多个子类,继承关系如下图所示,可以实现不同的数据输出流。
OutputStream类常用方法如下表所示。
方法名称 | 功能描述 |
---|---|
void write(int c) | 将指定的字节输出到输出流中,其中c代表字节 |
void write(byte[] b) | 将字节数组b中的数据输出到指定输出流 |
void write(byte[] b, int off, int len) | 将字节数组中从off位置开始,长度为len的数据输出到指定输出流 |
flush() | 刷新当前输出流,并强制写入所有缓冲的字节数据 |
close() | 关闭当前输出流,并释放任何与之关联的系统资源 |
2 FileInputStream & FileOutputStream
2.1 FileInputStream(访问文件)
FileInputStream是InputStream类的子类,实现了文件的读取,是文件字节输入流。常用构造方法有如下两种。
(1) FileInputStream(String filePath);
try {
FileInputStream fis2 = new FileInputStream("H:\\testIO\\test.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
(2) FileInputStream(File file);
File file = new File("H:\\testIO\\test.txt");
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
FileInputStream fis1 = new FileInputStream(file);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
FileInputStream测试代码:
package testIO;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.File;
public class TestFileInputStream {
public static void main(String[] args){
File file = new File("H:\\testIO\\test.txt");
try {
if(!file.exists()){
file.createNewFile();
}
FileInputStream fis = new FileInputStream(file);
byte[] b = new byte[512];
int rs = 0;
System.out.println("output the context of file: ");
while((rs = fis.read(b)) > 0){
String s = new String(b, 0, rs);
System.out.println(s);
}
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
output the context of file:
This is my book!
2.2 FileOutputStream(写入文件)
FileOutputStream类是OutputStream类的子类,实现文件的写入,能够以字节形式写入文件中,该类的所有方法都是从OutputStream类继承并重写的。构造方法有三种。
(1) FileOutputStream(String filePath);
(2) FileOutputStream(File file); 对原文件内容进行覆盖。
(3) FileOutputStream(File file, true); 对原文件内容进行追加。
FileOutputStream测试代码:
package testIO;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestFileOutputStream {
public static void main(String[] args) throws IOException{
File file = new File("H:\\testIO\\test1.txt");
if(!file.exists()){
file.createNewFile();
}
byte[] bytes = new byte[512];
System.out.println("please input the context: ");
int b = System.in.read(bytes);
FileOutputStream fos = new FileOutputStream(file, true);
fos.write(bytes, 0, b);
fos.close();
}
}
3 ByteArrayInputStream & ByteArrayOutputStream
3.1 ByteArrayInputStream(访问字节数组)
ByteArrayInputStream类从内存中的字节数组中读取数据,因此它的数据源是一个字节数组。关闭ByteArrayInputStream输入流之后,类中的方法仍可被调用。构造方法有两种。
(1) ByteArrayInputStream(byte[] buf);
(2) ByteArrayInputStream(byte[] buf, int off, int len);
ByteArrayInputStream.read()方法读取输入流的下一个字节,read()方法不会锁住,read()方法返回值为0-255,如果流已经达到了它的结束则返回-1。
ByteArrayInputStream测试代码:
package testIO;
import java.io.IOException;
import java.io.ByteArrayInputStream;
public class TestByteArrayInputStream {
public static void main(String[] args) throws IOException{
byte[] buf = new byte[] {2, 15, 67, -1, -9, 9};
ByteArrayInputStream bais = new ByteArrayInputStream(buf, 1, 4);
int data;
while((data = bais.read()) != -1){
System.out.println(data);
}
bais.close();//ByteArrayInputStream的close()方法实际上不执行任何操作
}
}
运行结果:
15
67
255
247
解析:
以上字节数组输入流从字节数组buf的下标为1的元素开始读,一共读取4个元素。对于读到的每一个字节类型的元素,都会转换为int类型。
例如:对于字节类型的15,二进制形式为00001111,转换为int类型的二进制形式为
00000000 00000000 00000000 00001111,因此字节类型的15 转换为int类型仍然是15;对于字节类型的-1,二进制形式为 11111111,转换为int类型的二进制形式为
00000000 00000000 00000000 11111111,因此字节类型的-1 转换为int类型是255;对于字节类型的-9,二进制形式为 11110111,转换为int类型的二进制形式为 00000000 00000000 00000000 11110111,因此字节类型的-9转换为 int类型是 247。
以上字节数组输入流在读取了4个字节后,就达到了输入流的末尾,在执行read()方法,就会返回-1。
3.2 ByteArrayOutputStream(写入字节数组)
ByteArrayOutputStream类继承了OutputStream类,实现输出流中的数据被写入一个字节数组,缓冲区会随着数据的不断写入而自动增长。关闭一个字节数组输出流之后没有影响,这个类中的方法可以在流已关闭后被调用。构造方法有两种。
(1) ByteArrayOutputStream(); 将创建一个新的字节数组输出流,默认32字节的缓冲区。
(2) ByteArrayOutputStream(int size); 将创建一个新的字节数组输出流,具有指定大小size字节的缓冲容量。
常用方法如下:
方法名称 | 功能描述 |
---|---|
byte[] toByteArray() | 创建一个新分配的字节数组 |
String toString() | 将缓冲区的内容转换为使用平台默认字符集的字符串解码字节 |
String toString(String charsetName) | 通过使用指定charsetName解码字节将缓冲区的内容转换成一个字符串 |
void write(byte[] b, int off, int len) | 将指定的字节数组从off开始写入该字节数组输出流,写入长度为len |
void write(int b) | 将指定字节写入该字节数组输出流 |
void writeTo(OutputStream out) | 将该字节数组输出流的全部内容写入到指定的输出流参数 |
int size() | 返回缓冲区的当前大小 |
void reset() | 重置该字节数组输出流为零的计数字段,丢弃所有当前累计输出 |
void close() | 关闭字节数组输出流,但是对方法的调用不产生影响 |
ByteArrayOutputStream测试代码:
package testIO;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
public class TestByteArrayOutputStream {
public static void main(String[] args) throws IOException{
byte[] buf = new byte[]{2, 15, 67, -1, -9, 9};
ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
bos1.write(1);
bos1.write(2);
bos1.write(buf, 0, 4);
bos1.writeTo(bos2);
byte[] buf1 = bos1.toByteArray();
byte[] buf2 = bos2.toByteArray();
System.out.println("test1: ");
for(int i = 0; i < buf1.length; i++){
System.out.print(buf1[i] + " ");
}
System.out.println();
System.out.println("test2: ");
for(int i = 0; i < buf2.length; i++){
System.out.print(buf2[i] + " ");
}
System.out.println();
bos2.close();
bos1.close();
}
}
运行结果:
test1:
1 2 2 15 67 -1
test2:
1 2 2 15 67 -1