为了提高文章的可阅读性,在本文的示例程序中,对于异常的处理采取了直接抛出,减少了try/catch,使得代码简凑易读。请读者在实操时用try/catch代码块进行处理!
下面介绍这两个类的使用
新建一个文件"C_01.txt",写入Morning!
,共8个字节
FileInputStream
FileInputStream对象在创建时与文件建立了连接,用于从文件中读取原始字节流,因此不适合读取含有非单字节编码的符号(如中文)的文件。
1.流对象与文件建立连接
FileInputStream in = new FileInputStream(new File("C_01.txt"));
2.返回剩余可以被读取(或跳过)的字节数
System.out.println(in.available()); //8
3.判断流对象是否支持mark和reset
System.out.println(in.markSupported()); //false
4.读取并返回下一个字节
int read = in.read();
System.out.println((char)(read)); //M
byte[] bytes = new byte[10];
System.out.println(in.read(bytes)); //8
System.out.println(new String(bytes));//Morning!
6.读取指定长度的字节,从字节数组的的指定偏移量开始存放,,返回读取的字节数
int read(byte[] b,int off,int len)
byte[] bytes = new byte[20];
System.out.println(in.read(bytes,10,3)); //3
System.out.println((char)bytes[10]); //M
System.out.println((char)bytes[12]); //r
7.返回剩余的字节组成的字节数组
byte[] bytes = in.readAllBytes();
System.out.println(new String(bytes)); //Morning!
8.读取指定长度的字节,从字节数组的指定偏移量开始存放,返回读取的字节数
byte[] bytes = new byte[20];
int len = in.readNBytes(bytes,0,2);
System.out.println(len); //2
System.out.println(new String(bytes)); //Mo
9.读取指定长度的字节,返回一个字节数组
byte[] bytes = in.readNBytes(7);
System.out.println(bytes.length); //7
System.out.println(new String(bytes)); //Morning
10.跳过n个字节
in.skip(7);
System.out.println((char)in.read()); //!
in.close();
11.关闭流并释放资源
in.close();
FileOutputStream
FileOuputStream对象用于向文件写原始入字节。注意,有些系统不支持多个FileOutputStream对象同时对同一个文件进行写入。
1.流对象与文件建立连接
FileOutputStream out = new FileOutputStream(new File("C_01.txt"));
2.向文件中写入字节数组bytes的内容,C_01.txt内容变为Hello World
byte[] bytes = "Hello World".getBytes();
out.write(bytes);
out.flush(); //强制刷新,使得流中的数据输入文件
3.将bytes数组从偏移量6开始的5个字节内容写入文件,C_01.txt内容变为World
byte[] bytes = "Hello World".getBytes();
out.write(bytes,6,5);
out.flush();
4.将指定字节写入文件,C_01.txt内容变为e
byte[] bytes = "Hello World".getBytes();
out.write(bytes[1]);
输入流与a.txt建立连接,输出流与b.txt建立连接,通过输入流的transferTo
方法,将a文件的字节传输到b文件,并返回传输的字节数量
in = new FileInputStream(new File("a.txt"));
out = new FileOutputStream(new File("b.txt"));
System.out.println(in.transferTo(out)); //返回传输的字节数量
BufferedInputStream
BufferedInputStream对象中包含了一个内置的数组;同时,它拥有mark和reset的功能–就像是一个指针,标记了流中的一个位置,调用reset后,会回到该位置
1.与FileInputStream使用方式一样的API,不再赘述
C_03_1.txt
文件中写有Morning!
InputStream in = new FileInputStream(new File("C_03_1.txt"));
BufferedInputStream bufferedInputStream = new BufferedInputStream(in);
System.out.println(bufferedInputStream.available()); //8
System.out.println(bufferedInputStream.markSupported()); //true
byte[] bytes = bufferedInputStream.readAllBytes();
System.out.println(new String(bytes)); //Morning!
2.mark
与reset
System.out.println((char) bufferedInputStream.read());//M
//传入的参数是:调用mark()方法之后到调用reset()方法失败之前,允许的最大预读数
bufferedInputStream.mark(0);
System.out.println((char) bufferedInputStream.read());//o
System.out.println((char) bufferedInputStream.read());//r
//返回mark的位置
bufferedInputStream.reset();
System.out.println((char) bufferedInputStream.read());//o
BufferedOutputStream
通过使用BufferedOutputStream对象 应用程序可以将字节写入底层输出流(如FileOutputStream),而不必对写入的每个字节都导致对底层系统的调用。
该类的使用与FileOutputStream相似,不再赘述
OutputStream out = new FileOutputStream(new File("C_03_2.txt"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out);
//将Microsoft写入C_03_2.txt中
bufferedOutputStream.write("Microsoft".getBytes());
bufferedOutputStream.flush();
bufferedOutputStream.close();
ByteArrayInputStream
ByteArrayInputStream对象建立的是与byte数组的“连接”,也就是对原生数组的包装。通过阅读其构造函数的源代码即可发现这一点。
因此,调用此类对象的close()
方法是不起效果的
构造函数源代码:
public ByteArrayInputStream(byte buf[]) {
this.buf = buf; //让内置的buf引用指向传入的数组
this.pos = 0; //维护下一个要访问的位置的“指针”
this.count = buf.length;
}
public ByteArrayInputStream(byte buf[], int offset, int length) {
this.buf = buf;
this.pos = offset;
this.count = Math.min(offset + length, buf.length);
this.mark = offset;
}
因此,ByteArrayInputStream类的使用也是很简单的
byte[] bytes = "China".getBytes();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
System.out.println(byteArrayInputStream.markSupported()); //true
System.out.println((char) byteArrayInputStream.read()); //C
byteArrayInputStream.mark(0);
System.out.println((char) byteArrayInputStream.read()); //h
System.out.println((char) byteArrayInputStream.read()); //i
byteArrayInputStream.reset();
System.out.println((char) byteArrayInputStream.read()); //h
ByteArrayOutputStream
还是通过构造器的源码来看这个类
//创建构造方法参数指定大小的内置数组
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ size);
}
buf = new byte[size];
}
//若不传入参数,则默认创建32字节大小的内置数组
public ByteArrayOutputStream() {
this(32);
}
下面是ByteArrayOutputStream的用法
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(16);
//向内置数组写入数据
byteArrayOutputStream.write(65); //写入A
byteArrayOutputStream.write(66); //写入B
byteArrayOutputStream.writeBytes("ab".getBytes()); //写入ab
System.out.println(byteArrayOutputStream.size()); //4
System.out.println(byteArrayOutputStream.toString()); //ABab
System.out.println(new String(byteArrayOutputStream.toByteArray())); //ABab
FileOutputStream fileOutputStream = new FileOutputStream(new File("C_02.txt"));
byteArrayOutputStream.writeTo(fileOutputStream); //将内置数组的内容通过fileOutputStream写入C_02.txt
DataInputStream类对象使得程序可以从InputStream流中读取Java原生类型,对应的也就是DataOutputStream对象可以向流中写入Java原生类型。注意:读和写必须遵循一样的顺序与类型!
以下程序通过DataOutputStream通过OuputStream流,向文件中写入三个Java原生数据类型的数,再通过DataInputStream读出
File file = new File("C_04.txt");
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(file);
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
//向C_04.txt写入三个Java原生类型的数据
dataOutputStream.writeBoolean(true);
dataOutputStream.writeInt(888);
dataOutputStream.writeLong(999L);
fileOutputStream.flush();
//从C_04.txt中读出原生数据
System.out.println(dataInputStream.readBoolean()); //true
System.out.println(dataInputStream.readInt()); //888
System.out.println(dataInputStream.readLong()); //999
如果理解了DataInpuStream和DataOutputStream的作用,那么接下来这两个类也自然好理解了。
ObjectOutputStream通过OuputStream向文件中写入序列化的对象或Java原生类型,相当于是序列化的过程。而ObjectInpuStream通过InpuStream从文件中读出内容,经过反序列化,还原出对象或原生Java类型。
下面这个例子,将Car对象通过ObjectOutputStream序列化写入文件,再通过ObjectInputStream反序列化读出。
其中Car和Engine对象是两个普通的Java bean,Engine与Car是组合关系。
//1.序列化存入
//创建一个对象car
Car car = new Car("BWM",10000.983D,new Engine("发动机A",100.10D));
File file = new File("C_05.txt");
FileOutputStream fileOutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
fileOutputStream = new FileOutputStream(file);
objectOutputStream = new ObjectOutputStream(fileOutputStream);
//向文件中写入car
objectOutputStream.writeObject(car);
fileOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//2.反序列化读出
FileInputStream fileInputStream = null;
ObjectInputStream objectInputStream = null;
try {
fileInputStream = new FileInputStream(file);
objectInputStream= new ObjectInputStream(fileInputStream);
//从文件中读出car
Object obj = objectInputStream.readObject();
Car c = (Car)obj;
System.out.println(c);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}