您的位置:首页 > 编程语言 > Java开发

[学习笔记]Java IO之字节流

2016-04-16 13:44 483 查看

1.概述

Java中使用流技术来实现设备间数据的传输,其操作对象是数据,采用的方式是流(类似水流)。

2.特点

按流的方向可分为输入流和输出流。
按流的内容可分为字节流和字符流。
按流的目标可分为键盘/屏幕,内存,文件和网络。
字节流的基类为InputStream/OutputStream,字符流的基类为Reader/Writer,且子类均以基类为后缀命名。
除了系统内置的标准输入输出流,其他流一般用完需要关闭,否则占用系统资源,特别是在多线程程序中导致效率低下。


字节流概述

字节流理论上可以处理任何数据。
字节流可以不经过缓冲直接向外围设备读写数据。


文件字节流

1.FileInputStream类

概述

源:文件,内容:字节,方向:输入。
可以将文件中的数据按单个字节读取,类型为int,若文件结束返回-1,否则返回该字节,高位补0。
可以将文件中的数据按多个字节读取到byte型数组中,若文件结束返回-1,否则返回读取到的字节数。

构造器

FileInputStream(Filefile)
FileInputStream(FileDescriptorfdObj)
FileInputStream(Stringname)

常用方法

获取文件中还未读取剩余的字节数

intavailable()
关闭流

voidclose()
读取字节数据,文件末尾返回-1

intread()

intread(byte[]b)

intread(byte[]b,intoff,intlen)
跳过读取字节数

longskip(longn)

示例

packageio.bytestream;importjava.io.File;importjava.io.FileInputStream;importjava.io.IOException;publicclassByteFileInputDemo{publicstaticvoidmain(String[]args)throwsIOException{Filefile=newFile("temp\\file.txt");//一次读取一个字节FileInputStreamfis=newFileInputStream(file);//FileNotFoundExceptionintch=0;while((ch=fis.read())!=-1){//IOException//FileInputStream.available():返回文件剩余字节数。System.out.println("available="+fis.available()//IOException+"ch="+(char)ch);}fis.close();//IOException//有缓冲区的读取fis=newFileInputStream(file);byte[]buf=newbyte[1024];//长度可以定义成1024的整数倍。intlen=0;while((len=fis.read(buf))!=-1){System.out.println(newString(buf,0,len));}fis.close();}}


2.FileOutputStream类

概述

目标:文件,内容:字节,方向:输出。
可以选择新文件方式创建对象,也可以选择数据追加方式创建对象。
如果是新文件方式创建对象,如果该文件存在,则覆盖。
可以将文件中的数据按单个字节写入,类型为int,若文件结束返回-1,否则返回该字节,高位补0。
可以将文件中的数据按多个字节读取到byte型数组中,若文件结束返回-1,否则返回读取到的字节数。

构造器

FileOutputStream(Filefile)
FileOutputStream(Filefile,booleanappend)
FileOutputStream(Stringname)
FileOutputStream(Stringname,booleanappend)

常用方法

关闭流

voidclose()
写入数据

voidwrite(byte[]b)

voidwrite(byte[]b,intoff,intlen)
写入字节数据(int参数的低8位)

voidwrite(intb)

示例

packageio.bytestream;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
publicclassByteFileOutputDemo{
privatestaticfinalStringLINE_SEPARATOR=System.lineSeparator();
publicstaticvoidmain(String[]args){
Filedir=newFile("temp");
if(!dir.exists()){
dir.mkdir();
}
Filefile=newFile(dir,"file.txt");
try{
fileOutput(file,"java");
}catch(IOExceptione){
System.out.println("文件写入异常!");
e.printStackTrace();
}
Stringstr=LINE_SEPARATOR+"itheima";
appendFileOutput(file,str);
}
publicstaticvoidappendFileOutput(Filefile,Stringdata){
//1.fos需要在finally中释放文件,所以fos声明必须在try-catch语句之外。
FileOutputStreamfos=null;
try{
//2.创建对象和文件写入均可能有异常发生。
//FileOutputStream(Filefile,booleanappend);续写。
fos=newFileOutputStream(file,true);
fos.write(data.getBytes());
}catch(IOExceptione){
System.out.println("文件创建异常!");
e.printStackTrace();
}finally{
//3.关闭文件也可能有异常发生,这里由于不确定fos是否成功创建对象,所以需要判断。
if(fos!=null){
try{
fos.close();
}catch(IOExceptione){
//4.一般地,关闭文件异常转换为RuntimeException强制终止程序。
System.out.println("文件关闭异常!");
thrownewRuntimeException();
}
}
}
}
publicstaticvoidfileOutput(Filefile,Stringdata)throwsIOException{
//输出流目的是文件,会自动创建。如果文件存在,则覆盖。
FileOutputStreamfos=newFileOutputStream(file);
fos.write(data.getBytes());
fos.close();
}
}



缓冲字节流

1.BufferedInputStream类

概述

该类是InputStream类的带缓冲包装类,提供缓冲功能。

构造器

BufferedInputStream(InputStreamin)
指定缓冲区大小构建流

BufferedInputStream(InputStreamin,intsize)

常用方法

与FileInputStream类似

2.BufferedOutputStream类

概述

该类是OutputStream类的带缓冲包装类,提供缓冲功能。

构造器

BufferedOutputStream(OutputStreamout)
指定缓冲区大小构建流

BufferedOutputStream(OutputStreamout,intsize)

常用方法

与FileOutputStream类似

将缓冲区中的数据强制写入文件

voidflush()


注意

读取单个字节时,返回类型为int,这时低8位是读取到的数据,如果到流的末尾,则返回-1。
写入单个字节时,写入的数据类型为int,但是只有低8位会被写入。
流中的byte和int之间的转换不是一般的数据类型转换,数据符号位不影响最终数据,即可以看成是无符号数据。
缓冲区的作用是尽可能避免外存设备和内存设备速度差别所造成的资源浪费。
带缓冲字节流原理是内置了一个缓冲区,每次读取或写入数据就必须经过缓冲区,每次读取都将读取缓冲区长度的数据,而写入时是当缓冲区满,或者flush亦或是close执行时,才将缓冲区数据写入外存,这样避免了外存的频繁访问,提高速率。
BufferedInputStream.read(byte[])方法为InputStream类中的方法,并没有覆盖,如何使用BufferedInputStream类中的缓存呢?

因为结构如下:

BufferedInputStream.read(byte[])调用

->FilterInputStream.read(byteb[])调用

->FilterInputStream.read(byteb[],intoff,intlen)调用

->InputStream.read(byteb[],intoff,intlen),函数中调用

->InputStream.read(),而该方法为抽象方法,最终调用

->BufferedInputStream.read()
必要时才使用flush(常在多线程并发访问时使用),频繁使用flush将降低写入效率,并且流不用时应及时关闭。
异常处理

a.由于流必须关闭,所以应在finally中执行。

b.因为流对象的建立可能报FileNotFoundException,而流关闭必须在finally中执行,所以流变量定义必须在try前,而对象的创建在try中。

c.如果流没有创建成功,这时将无法进行关闭动作,所以finally中必须进行判断。

d.一般流关闭错误较为严重,一般在catch中再次抛出RuntimeException终止程序。


案例

复制文件

packageio.bytestream;
importjava.io.BufferedInputStream;
importjava.io.BufferedOutputStream;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.io.IOException;
publicclassByteFileCopy{
publicstaticvoidmain(String[]args){
FileoldFile=newFile("temp//byte.ape");
FilenewFile1=newFile("temp//byte_copy1.ape");
FilenewFile2=newFile("temp//byte_copy2.ape");
//使用自定义缓冲区复制文件
try{
copyFile(oldFile,newFile1);
}catch(IOExceptione){
e.printStackTrace();
}
//使用BufferedInputStream和BufferedOutputStream复制文件
try{
copyFileUseBuf(oldFile,newFile2);
}catch(IOExceptione){
e.printStackTrace();
}
}
//使用自定义缓冲区复制文件
publicstaticvoidcopyFile(FileoldFile,FilenewFile)throwsIOException{
FileInputStreamoldFIS=newFileInputStream(oldFile);
FileOutputStreamnewFOS=newFileOutputStream(newFile);
byte[]buffer=newbyte[1024];
intlen=-1;
while((len=oldFIS.read(buffer))!=-1){
newFOS.write(buffer,0,len);
}
oldFIS.close();
newFOS.close();
}
//使用BufferedInputStream和BufferedOutputStream复制文件
publicstaticvoidcopyFileUseBuf(FileoldFile,FilenewFile)throwsIOException{
FileInputStreamoldFIS=newFileInputStream(oldFile);
FileOutputStreamnewFOS=newFileOutputStream(newFile);
BufferedInputStreambis=newBufferedInputStream(oldFIS);
BufferedOutputStreambos=newBufferedOutputStream(newFOS);
intch=-1;
while((ch=bis.read())!=-1){
bos.write(ch);
}
//使用双层缓冲可以进一步提高效率,减少函数调用的开销
byte[]buffer=newbyte[1024];
intlen=-1;
while((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}
bis.close();
bos.close();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: