在上一篇文章中我们对InputStream的read方法和OutputStream的write方法进行了讲解,希望能对大家所有帮助。今天我们看下两个类剩余的几个方法
InputStream
mark(int readLimits)
reset()
这两个方法常常组合使用,java文档上说mark方法记录在当前流中的读取位置,其中的参数readLimits表示使mark生效的最大已读取字节数,很拗口,简单来说就是从上次reset起,一旦读取的字节数超过了readLimits,那么mark不再生效。
注意:实际上并不是这样,因为即使从上次
reset起读取的字节数超过了readLimits,reset仍然生效,stackoverflow上也有专门讨论:stackoverflow.com/questions/4… 有人建议把上述描述中的最大改成最小,个人表示同意
reset表示将当前读取位置恢复到最近一次mark的位置
注意:
InputStream的子类会重写mark和reset方法,比如ByteArrayInputStream和CharArrayInputStream下面例子会详细说明
private static void byteArrayCase(){
try(InputStream inputStream = new ByteArrayInputStream("abcdef".getBytes())){
//第一次读取一个字节
int data = inputStream.read();
System.out.println((char)data);
//标记当前位置 1 并限制最多读取两个字节
inputStream.mark(2);
//继续读取三个字节
byte[] buffer = new byte[3];
data = inputStream.read(buffer);
for(int i=0; i< data; i++){
System.out.print((char)buffer[i]);
}
System.out.println();
//重置到位置1
inputStream.reset();
//第三次读完所有字节
while ((data = inputStream.read(buffer)) != -1){
for(int i=0; i< data; i++){
System.out.print((char)buffer[i]);
}
}
}
catch (IOException e){
e.printStackTrace();
}
}
输出
a
bcd
bcdef
上例先读取一个字节,然后设置mark,并且设置readLimits为2。此时readLimits大于已读取得的字节数,所以mark生效。然后再读取3个字节,然后调用reset,位置回到1,然后再读取,所以就是上面的结果。 上例readLimites大于已读取的字节数(严格意义上是上次调用了reset后读取的字节数),那如果小于是不是就真的不生效呢?看下例
private static void byteArrayCase1(){
try(InputStream inputStream = new ByteArrayInputStream("abcdef".getBytes())){
//读取三个字节
byte[] buffer = new byte[3];
int data = inputStream.read(buffer);
for(int i=0; i< data; i++){
System.out.print((char)buffer[i]);
}
System.out.println();
//标记当前位置 3 注意此时readLimits小于已读取得字节数3
inputStream.mark(2);
//再读取一个字节
data = inputStream.read();
System.out.println((char)data);
//重置到位置3
inputStream.reset();
//读完所有字节
while ((data = inputStream.read(buffer)) != -1){
for(int i=0; i< data; i++){
System.out.print((char)buffer[i]);
}
}
}
catch (IOException e){
e.printStackTrace();
}
}
输出
abc
d
defa
上例先读取3个字节,记录当前位置,注意此时readLimits小于已读取字节数,然后再读取一个字节,但是我们发现mark和reset仍然生效了。看了一下ByteArrayInputStream源码发现:Note: The readAheadLimit for this class has no meaning.意思就是说这个参数对于该类来说无意义。真是...
注意:
CharArrayInputStream也是这个样子的呦
对于使用BufferedInputStream的同学更要注意,因为它还跟BufferedInputStream的初始大小buffer有关系,比如下面代码
private static void bufferedInputStreamCase2(){
try(InputStream in = new ByteArrayInputStream("abcdef".getBytes());
BufferedInputStream bufferedInputStream = new BufferedInputStream(in,2);
){
//读取一个字节
int data = bufferedInputStream.read();
System.out.println((char)data);
//标记位置
bufferedInputStream.mark(1);
//读取三个字节
byte[] buffer = new byte[3];
data = bufferedInputStream.read(buffer);
for(int i=0; i<data; i++){
System.out.print((char)buffer[i]);
}
System.out.println();
bufferedInputStream.reset();
while ((data = bufferedInputStream.read(buffer)) != -1){
for(int i=0; i<data; i++){
System.out.print((char)buffer[i]);
}
}
}
catch (IOException e){
e.printStackTrace();
}
}
上面代码初始化了一个大小为2字节的BufferedInputStream,并且设置mark的readLimits的为1,当读取的字节数超过两者之间的最大值时,就会报IO异常,这个你可以作为练习试试,不断调整这三个值,看看观察的结果是否跟我一致,如果不一致敬请留言。
OutputStream
flush()
close()
这两个方法比较简单,第一个是冲刷OutputStream里的缓存,另一个是关闭输出流,释放资源。注意flush是冲刷输出流中的缓存,比如有的输出流内部维护者一个buffer,假定buffer的长度是1024,如果文件大小只有10字节,那么无论如何也填充不满这1024长度的buffer,那么该输出流就会等待下去,此时如果调用flush就可以得到这个10字节的内容。示例如下
private static void output(){
InputStream in = null;
OutputStream out = null;
BufferedOutputStream bOut = null;
try{
in = new FileInputStream("d:\\temp1.txt");
out = new FileOutputStream("d:\\temp1.txt");
bOut = new BufferedOutputStream(out,10);
bOut.write("Hello".getBytes());
//bOut.flush();
showContent(in);
}
catch (IOException e){
e.printStackTrace();
}
}
private static void showContent(InputStream in) throws IOException{
int data;
byte[] buffer = new byte[5];
while((data = in.read(buffer))!= -1){
for(int i=0; i< data; i++){
System.out.print((char)buffer[i]);
}
}
}
上面这个方法不能显示Hello,除非取消注释或者关闭bOut。大家可以作为练习试一下
注意:
flush冲刷的是输出流内部的缓存,如果是自己定义的缓存,那么无需调用也可以正常输出,比如下面的代码
private static void output3(){
InputStream in = null;
OutputStream out = null;
try{
int data;
byte[] buffer = new byte[20];
in = new ByteArrayInputStream("Hello world!".getBytes());
out = new FileOutputStream("d:\\temp1.txt");
while ((data = in.read(buffer)) != -1){
out.write(buffer,0,data);
}
showContent(new FileInputStream("d:\\temp1.txt"));
}
catch (IOException e){
e.printStackTrace();
}
}
private static void showContent(InputStream in) throws IOException{
int data;
byte[] buffer = new byte[5];
while((data = in.read(buffer))!= -1){
for(int i=0; i< data; i++){
System.out.print((char)buffer[i]);
}
}
}
上面代码仍然可以正常输出Hello world!,注意上面代码没有调用close或flush,这种写法只是为了方便展示效果,你应该及时关闭所有资源,大家可以作为练习来修改。