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

Java学习笔记之IO 2

2015-05-23 18:15 465 查看
IO学习笔记之字节流
一、IO流

1.概述:IO流用来处理设备之间的数据传输(如上传文件、下载文件),java对数据的操作是通过流的方式,java用于操作流的对象都在IO包中。

导语:把大象装进冰箱分3步,1打开冰箱门,2把大象放进去,3关闭冰箱门。

2.分类

2.1根据流向划分:

输入流:读取数据

输出流:写出数据

2.2根据流的类型划分:重点

字节流:

字节输入流:InputStream
字节输出流:OutputStream

字符流:

字符输入流:Reader
字符输出流:Writer

2.3常见问题:什么情况下使用字节流,什么时候使用字符流?

如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流,如果看不懂就使用字节流。字节流是万能的流,可以打开图片、视频、文档等各种格式的文件,推荐使用。

二、OutputStream类

概述:字节输出流,此抽象类是表示输出字节流的所有类的超类。

三、FileOutputStream类

3.1简介

FileOutputStream类继承OutputStream类,文件字节输出流是用于将数据写入
File
FileDescriptor
的输出流。
FileOutputStream
用于写入诸如图像数据之类的原始字节的流。从JDK1.0开始。

使用字节输出流的步骤:

1、打开文件(创建字节输出流对象)

2、写入数据

3、关闭文件(释放资源)。

3.2构造方法

publicFileOutputStream(Filefile)//通过给定的File对象创建字节输出流对象。

publicFileOutputStream(Filefile,booleanappend)//创建字节输出流对象,并可以在原有数据的末尾添加数据。

publicFileOutputStream(Stringname)通过给定的文件字符串路径来创建字节输出流对象。

publicFileOutputStream(Stringname,booleanappend)//创建字节输出流对象,并可以在原有数据的末尾添加数据。

构造方法抛出的异常

throwsFileNotFoundException如果该文件存在,但它是一个目录,而不是一个常规文件;或者该文件不存在,但无法创建它;抑或因为其他某些原因而无法打开

构造方法测试案例

public
class
FileOutputStreamDemo{
public
staticvoid
main(String[]
args)throwsFileNotFoundException{
//指定文件路径,创建文件对象,
Filefile=newFile("d:\\lee\\123.txt");
//根据文件对象,创建字节输出流对象。打开文件,如果文件不存在,创建后,打开
FileOutputStreamfos=newFileOutputStream(file);
//根据文件路径,创建字节输出流对象。打开文件,如果文件不存储,创建后,打开
//推荐使用
FileOutputStreamfos2=newFileOutputStream("d:\\lee\\111.txt");
}
}

输出结果:如图1所示



图1
3.3普通方法

父类OutputStream中的方法:

publicvoidwrite(intb)//写入一个字节

publicvoidwrite(byte[]buffer)//写入一个字节数组

publicvoidwrite(byte[]buffer,intstart,intlen)//写入一个字节数组的一部分

publicvoidclose()//释放与流对象相关的资源

publicvoid
flush
()
//刷新此输出流并强制写出所有缓冲的输出字节。

测试案例1:写数据

public
class
FileOutputStreamDemo2{
public
staticvoid
main(String[]
args)throwsIOException{
//根据文件路径,创建文件字节输出流对象,1打开文件
FileOutputStreamfos=
new
FileOutputStream("d:\\lee\\123.txt");
//2写数据
fos.write(97);//写一个字节,小a
//写一个字节数组,String中的getBytes()方法,把字符串转换成字节数组
fos.write("hello,Java".getBytes());
//写字节数组的一部分
byte[]bys={97,98,99,100};
fos.write(bys,1,2);
//刷新,文件较短的话可以不用刷新,当写入数据较大时推荐使用刷新功能
fos.flush();
//3关闭文件
fos.close();
}
}

输出结果如图2所示。



图2
测试案例2:追加模式写数据,

public
class
FileOutputStreamDemo3{
public
staticvoid
main(String[]
args)throwsIOException{
//1打开文件
//打开文件,并开启追加模式
FileOutputStreamfos=
new
FileOutputStream("d:\\lee\\123.txt",true);
//2写数据
fos.write('a');
//写字符串数组,\r\n:表示换行
fos.write("bcdeef\r\n".getBytes());
fos.write("ghijkl\r\n".getBytes());
//3关闭文件
fos.close();
}
}

输出结果如图3所示。



图3
注意:在eclipse中数据实现换行和追加写入:

Windows:\r\n

UnixLinux:\n

MacOS:\r

测试案例3:实际开发中FileOutputStream类的异常处理。

public
class
FileOutputStreamDemo4{
public
staticvoid
main(String[]
args){
FileOutputStreamfos=
null
;//把文件放在外面
try{
//1打开文件
fos=newFileOutputStream("fos.txt");
//2写数据
fos.write("Java".getBytes());
}catch(FileNotFoundExceptione){
e.printStackTrace();//打印错误信息
}catch(IOExceptione){
e.printStackTrace();//打印错误信息
}finally{
try{
//3关闭文件
fos.close();
}catch(IOExceptione){
e.printStackTrace();
}
}

}
}

注意:在实际开发中常用案例3中的异常处理方法,在学习过程中一般使用throws抛出异常,这种异常处理方式让代码显得简洁,但实际并没有处理异常,而是抛给了Java虚拟机解决。

四、InputStream类

概述:此抽象类是表示字节输入流的所有类的超类,从JDK1.0开始。

构造方法

publicInputStream()

常用方法

publicvoidclose
()//
关闭此输入流并释放与该流关联的所有系统资源。

publicabstractintread()//从输入流中读取数据的下一个字节。读到流末尾而没有可用的字节,则返回值
-1


publicintread(byte[]b)//从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。

publicvoidread(byte[]b,intoff,intlen)//将输入流中最多len个数据字节读入byte数组。读到流末尾而没有可用的字节,则返回值
-1


publicvoidreset()//将此流重新定位到最后一次对此输入流调用mark方法时的位置。

五、FileInputStream类

5.1简介

FileInputStream继承InputStream,从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。
FileInputStream
用于读取诸如图像数据之类的原始字节流。

使用字节输入流的步骤:

1、打开文件(创建字节输入流对象)

2、读取数据

3、关闭文件(释放资源)

5.2构造方法

publicFileInputStream(Filefile)throwsFileNotFoundException
//通过给定的File对象,创建一个字节输入流对象

publicFileInputStream(Stringname)throwsFileNotFoundException
//
通过给定的文件名路径,创建一个字节输入流对象,推荐使用

5.3普通方法

publicintread()//读取一个字节,读取到了流的末尾,返回-1。

publicintread(byte[]buffer)//读取一个字节数组,返回实际读取到的字节数量

测试案例1:用read()方法把某路径下的文件复制到指定路径下。一次读取一个字节,写入一个字节数据。

分析:

1:封装数据源与目的地
2:从数据源中读数据
3:把数据写到目的地
4:关闭流

图4为程序流程示意图



图4
public
class
FileInputStreamTest2{
public
staticvoid
main(String[]
args)throwsIOException{
//1封装数据源
FileInputStreamfis=newFileInputStream("d:\\lee\\psb.jpg");//可以是任意类型的文件
//封装目的地数据
FileOutputStreamfos=newFileOutputStream("c:\\lee\\222.jpg");
//定义一个变量保存读到的数据,该数据初始化为-1,表示默认文件为空。
intch=-1;
//2读取一个字节数据,当读到的数据不为空时(ch=-1),开始写数据
while((ch=fis.read())!=-1){
//3写一个字节数据
fos.write(ch);
}
//关闭流
fis.close();
fos.close();
}
}
注意:java中Unicode编码的汉字占2个字节,由2个负数组成。

Utf-8的汉字占3个字节,

Gbk的汉字占2个字节

Unicode编码的汉字测试代码:

public
class
StringCode{
public
staticvoid
main(String[]
args){
Stringstr=
"你好";
byte[]bys=str.getBytes();//把字符串转成字节数组
System.out.println(Arrays.toString(bys));
}
}

输出结果:

[-60,-29,-70,-61]

测试案例2:用read(byte[]buffer)方法把某路径下的文件复制到指定路径下。一次读取一个数组字节,写入一个数组字节数据。

public
class
FileIntputStreamTest{
public
staticvoid
main(String[]
args)throwsIOException{

//1、封装数据源
FileInputStreamfis=
new
FileInputStream("d:\\lee\\可爱颂.mp4");//可以是任意类型的文件
//封装目的地
FileOutputStreamfos=
new
FileOutputStream("c:\\lee\\ke.mp4");
//定义一个数组,一次读写一个数组
byte
buffer[]=new
byte
[100];//byte范围:-128~127
//定义一个用来保存每一次读到新数据的个数,默认文件为空。
int
count=-1;
//2、读一个数组数据,read(buffer)方法返回实际读到字节的个数
while((count=fis.read(buffer))!=-1){
//3、写一个数组数据,
//注意:读取多少个数据,就写入多少个数据
fos.write(buffer,0,count);
}
//4、关闭流
fis.close();
fos.close();
}
}

注意:同过对比表明,一次读写一个数组的方式复制文件时速度比一次读写一个字节数据时快很多。

六、BufferedOutputStream类

概述:字节缓冲输出流,写出数据。该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。间接继承OutputStream类。从JDK1.0开始。

构造方法

publicBufferedOutputStream(OutputStreamos)//把一个基本的字节输出流,包装成一个高效的字节缓冲输出流对象。默认缓冲区大小为8K,8192个字节。

publicBufferedOutputStream(OutputStreamos,intsize)//创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

常用方法

publicvoid
flush
()
//刷新此缓冲的输出流

publicvoid
write
(intb)
//写一个字节的数据。效率低

publicvoid
write
(byte[]b,intoff,intlen)
//写一个字节数组的一部分。效率高。

使用字节缓冲输出流的步骤

1、打开文件(创建字节缓冲输出流)

2、写取数据

3、关闭文件(释放资源)

测试案例

public
class
BufferedOutputStreamDemo{
public
staticvoid
main(String[]
args)throwsIOException{
//1、创建一个流对象
//OutputStreamos=newFileOutputStream("d:\\222.txt");
//BufferedOutputStream
bos
=newBufferedOutputStream(os);
//把基本的输出流对象包装成一个高效的缓冲输出流对象。
BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream("d:\\lee\\222.txt"));//匿名对象方式,推荐使用
//2、写数据
bos.write("hellojava".getBytes());
//3、关闭流
bos.close();
}
}

输出结果,如图



图5
七、BufferedInputStream类

概述:字节缓冲输入流,读取数据。间接继承InputStream类。
BufferedInputStream
为另一个输入流添加一些功能,即缓冲输入以及支持
mark
reset
方法的能力。从JDK1.0开始。

构造方法

publicBufferedInputStream(InputStreamos)//把一个基本的字节输入流,包装成一个高效的字节缓冲输入流对象

publicBufferedInputStream(InputStreamos,intsize)

常用方法

publicintread()//读一个字节,如果到达流末尾,则返回
-1


publicintread(byte[]b,intoff,intlen)//读一个字节数组的一部分,如果读到流末尾返回
-1
。否则此方法返回实际读取的字节数。

publicvoidclose()//关闭此输入流并释放与该流关联的所有系统资源。

使用字节缓冲输入流的步骤

1、打开文件(创建字节缓冲输入流)

2、读取数据

3、关闭文件(释放资源)

4.测试案例

public
class
BufferedInputStreamDemo{
public
staticvoid
main(String[]
args)throwsIOException{
//1、创建流对象
BufferedInputStreambis=newBufferedInputStream(newFileInputStream("d:\\lee\\222.txt"));//匿名对象方式
//2、读数据
/*
//方式一:一次一个字节
intch=-1;//记录每次读的字节
while((ch=bis.read())!=-1){
//3、写数据,直接打印到控制台
System.out.print((char)ch);
}
*/
//方式二:一次一个字节数组,推荐使用
byte[]buffer=newbyte[100];
intlen=-1;//用来记录每次读的新字节的个数
while((len=bis.read(buffer))!=-1){
//3、写数据,直接打印到控制台
//读到多少个字节数据,就写多少个字节数据
System.out.println(newString(buffer,0,len)
);
//把数组封装成一个对象,打印该对象信息
}
//4、关闭流
bis.close();
}
}

输出结果:hellojava

5.综合练习:

用字节流复制一个视频文件(可以是任意格式的文件)的4种方式

4种方式
基本字节流,一次一个字节
基本字节流,一次一个字节数组
高效字节流,一次一个字节
高效字节流,一次一个字节数组

测试代码:

public
class
CopyVideo{
public
staticvoid
main(String[]
args)throwsIOException{
long
start=System.currentTimeMillis();//起始时间
method1("d:\\lee\\TED.mp4","c:\\lee\\1.mp4");
//method2("d:\\lee\\TED.mp4","c:\\lee\\2.mp4");
//method3("d:\\lee\\TED.mp4","c:\\lee\\3.mp4");
//method4("d:\\lee\\TED.mp4","c:\\lee\\4.mp4");
long
end=System.currentTimeMillis();//结束时间
System.out.println("共耗时"+(end
-start)+"毫秒");
}
//方式4:高效的字节流,一次一个字节数组
public
staticvoid
method4(String
src,Stringdest)throwsIOException{
//1、数据源
BufferedInputStreambis=newBufferedInputStream(newFileInputStream(src));
//目的地
BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream(dest)
);
byte[]buffer=newbyte[1024];
int
len=-1;
//2、读一个字节数组数据
while((len=bis.read(buffer))!=-1){
//3、写一个字节数组数据
bos.write(buffer,0,len);
}
//4、关闭流
bis.close();
bos.close();
}
//方式3:高效的字节流,一个一个字节
public
staticvoid
method3(String
src,Stringdest)throwsIOException{
//1、数据源
BufferedInputStreambis=newBufferedInputStream(newFileInputStream(src));
//目的地
BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream(dest));
int
ch=-1;
//2、读一个字节数据
while((ch=bis.read())!=-1){
//3、写一个字节数据
bos.write(ch);
}
//4、关闭流
bos.close();
bis.close();
}
//方式2:基本的字节流,一次一个字节数组
public
staticvoid
method2(String
src,Stringdest)throwsIOException{
//1、数据源
FileInputStreamfis=
new
FileInputStream(src);
//目的地
FileOutputStreamfos=
new
FileOutputStream(dest);
byte[]buffer=newbyte[1024];//1kb
=1024字节
//2、读一个字节数组数据
int
len=-1;
while((len=fis.read(buffer))!=-1){
//3、写一个字节数组数据
fos.write(buffer,0,len);
}
//4、关闭流
fos.close();
fis.close();
}
//方式1:基本的字节流,一次一个字节
public
staticvoid
method1(String
src,Stringdest)throwsIOException{
//1、数据源
FileInputStreamfis=
new
FileInputStream(src);
//目的地
FileOutputStreamfos=
new
FileOutputStream(dest);
int
ch=-1;
//2、读一个字节数据
while((ch=fis.read())!=-1){
//3、写一个字节数据
fos.write(ch);
}
//4、关闭
fis.close();
fos.close();
}
}

分4次运行,输出结果:

方式1:共耗时143448毫秒

方式2:共耗时227毫秒

方式3:共耗时860毫秒

方式4:共耗时74毫秒

源文件大小:



目的地文件:



通过对比发现,高效缓冲流一次读写一个字节数组的方式在拷贝文件时数度最快,推荐使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: