IO性能分析Word文件下载.docx
- 文档编号:16179785
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:24
- 大小:24.04KB
IO性能分析Word文件下载.docx
《IO性能分析Word文件下载.docx》由会员分享,可在线阅读,更多相关《IO性能分析Word文件下载.docx(24页珍藏版)》请在冰豆网上搜索。
使用缓存减少读写次数开销
使用缓冲加速文件读取的示例:
对于一个1MB的输入文件,以秒为单位的执行时间是:
FileInputStream的read方法,每次读取一个字节,不用缓冲
6.9秒
BufferedInputStream的read方法使用BufferedInputStream
0.9秒
FileInputStream的read方法读取数据到直接缓冲
0.4秒
或者说在最慢的方法和最快的方法间是17比1的不同。
这个巨大的加速并不能证明你应该总是使用第三种方法,即自己做缓冲。
这可能是一个错误的倾向特别是在处理文件结束事件时没有仔细的实现。
在可读性上它也没有其它方法好。
但是记住时间花费在哪儿了以及在必要的时候如何矫正是很有用。
方法2或许是对于大多应用的"
正确"
方法.
方法2和3使用了缓冲技术,大块文件被从磁盘读取,然后每次访问一个字节或字符。
缓冲是一个基本而重要的加速I/O的技术,而且有几个类支持缓冲(BufferedInputStream用于字节,BufferedReader用于字符)。
缓冲区越大I/O越快吗?
典型的Java缓冲区长1024或者2048字节,一个更大的缓冲区有可能加速I/O但比重很小,大约5到10%。
方法1:
读方法
第一个方法简单的使用FileInputStream的read方法:
FileInputStream的read方法每次读取文件的下一个字节,触发了大量的底层运行时系统调用
优点:
编码简单,适用于小文件
缺点:
读写频繁,不适用于大文件
importjava.io.*;
publicclassintro1{
publicstaticvoidmain(Stringargs[]){
if(args.length!
=1){
System.err.println("
missingfilename"
);
System.exit
(1);
}
try{
FileInputStreamfis=newFileInputStream(args[0]);
//建立指向文件的读写流
intcnt=0;
intb;
while((b=fis.read())!
=-1){
//FileInputStream的read方法每次读取文件一个字节
if(b=='
\n'
)
cnt++;
fis.close();
System.out.println(cnt);
catch(IOExceptione){
System.err.println(e);
方法2:
使用大缓冲区
第二种方法使用大缓冲区避免了上面的问题:
BufferedInputStream的read方法把文件的字节块读入缓冲区,然后每次读取一个字节,每次填充缓冲只需要访问一次底层存储接口
避免每个字节的底层读取,编码相对不复杂
缓存占用了小量内存
publicclassintro2{
System.exit
(1);
FileInputStreamfis=
newFileInputStream(args[0]);
BufferedInputStreambis=newBufferedInputStream(fis);
//把文件读取流指向缓冲区
while((b=bis.read())!
=-1){
//BufferedInputStream的read方法把文件的字节块独
//入缓冲区BufferedInputStream,然后每次读取一个字节
cnt++;
bis.close();
}
方法3:
直接缓冲
FileInputStream的read方法直接读入字节块到直接缓冲buf,然后每次读取一个字节。
速度最快,
编码稍微复杂,可读性差,占用了小量内存,
publicclassintro3{
bytebuf[]=newbyte[2048];
intn;
while((n=fis.read(buf))!
=-1){//FileInputStream的read方法直接读入字节块到
//直接缓冲buf,然后每次读取一个字节
for(inti=0;
i<
n;
i++){
if(buf[i]=='
方法4:
缓冲整个文件
缓冲的极端情况是事先决定整个文件的长度,然后读取整个文件。
把文件底层读取降到最少,一次,
大文件会耗尽内存。
publicclassreadfile{
System.err.println("
intlen=(int)(newFile(args[0]).length());
bytebuf[]=newbyte[len];
//建立直接缓冲
fis.read(buf);
//读取整个文件
len;
这个方法很方便,在这里文件被当作一个字节数组。
但是有一个明显得问题是有可能没有读取一个巨大的文件的足够的内存。
缓冲的另一个方面是向窗口终端的文本输出。
缺省情况下,System.out(一个PrintStream)是行缓冲的,这意味着在遇到一个新行符后输出缓冲区被提交。
格式化的代价
实际上向文件写数据只是输出代价的一部分。
另一个可观的代价是数据格式化。
考虑下面的字符输出程序
性能对比结果为:
这些程序产生同样的输出。
运行时间是:
格式化方法
示例语句
运行时间
简单的输出一个固定字符
System.out.print(s);
1.3秒
使用简单格式"
+"
Strings=字符+字符,
1.8秒
使用java.text包中的MessageFormat类的对象方法
Strings=fmt.format(values);
7.8秒
使用java.text包中的MessageFormat类的静态方法
7.8*1.3秒
最慢的和最快的大约是6比1。
如果格式没有预编译第三种方法将更慢,使用静态的方法代替:
第三个方法比前两种方法慢很多的事实并不意味着你不应该使用它,而是你要意识到时间上的开销。
在国际化的情况下信息格式化是很重要的,关心这个问题的应用程序通常从一个绑定的资源中读取格式然后使用它。
方法1,简单的输出一个固定的字符串,了解固有的I/O开销:
publicclassformat1{
publicstaticvoidmain(Stringargs[]){
finalintCOUNT=25000;
for(inti=1;
=COUNT;
Strings="
Thesquareof5is25\n"
;
System.out.print(s);
方法2,使用简单格式"
:
publicclassformat2{
intn=5;
Thesquareof"
+n+"
is"
+
n*n+"
\n"
方法3,第三种方法使用java.text包中的MessageFormat类的对象方法:
importjava.text.*;
publicclassformat3{
MessageFormatfmt=
newMessageFormat("
Thesquareof{0}is{1}\n"
Objectvalues[]=newObject[2];
values[0]=newInteger(n);
values[1]=newInteger(n*n);
Strings=fmt.format(values);
方法4,使用MessageFormat.format(String,Object[])类的静态方法
publicclassformat4{
Stringfmt="
Strings=
MessageFormat.format(fmt,values);
这比前一个例子多花费1/3的时间。
随机访问的性能开销
RandomAccessFile是一个进行随机文件I/O(在字节层次上)的类。
这个类提供一个seek方法,和C/C++中的相似,移动文件指针到任意的位置,然后从那个位置字节可以被读取或写入。
seek方法访问底层的运行时系统因此往往是消耗巨大的。
一个更好的代替是在RandomAccessFile上建立你自己的缓冲,并实现一个直接的字节read方法。
read方法的参数是字节偏移量(>
=0)。
这样的一个例子是:
这个程序简单的读取字节序列然后输出它们。
适用的情况:
如果有访问位置,这个技术是很有用的,文件中的附近字节几乎在同时被读取。
例如,如果你在一个排序的文件上实现二分法查找,这个方法可能很有用。
不适用的情况:
如果你在一个巨大的文件上的任意点做随机访问的话就没有太大价值。
publicclassReadRandom{
privatestaticfinalintDEFAULT_BUFSIZE=4096;
privateRandomAccessFileraf;
privatebyteinbuf[];
privatelongstartpos=-1;
privatelongendpos=-1;
privateintbufsize;
publicReadRandom(Stringname)
throwsFileNotFoundException{
this(name,DEFAULT_BUFSIZE);
publicReadRandom(Stringname,intb)
raf=newRandomAccessFile(name,"
r"
bufsize=b;
inbuf=newbyte[bufsize];
publicintread(longpos){
if(pos<
startpos||pos>
endpos){
longblockstart=(pos/bufsize)*bufsize;
raf.seek(blockstart);
n=raf.read(inbuf);
return-1;
startpos=blockstart;
endpos=blockstart+n-1;
endpos)
returninbuf[(int)(pos-startpos)]&
0xffff;
publicvoidclose()throwsIOException{
raf.close();
ReadRandomrr=newReadRandom(args[0]);
longpos=0;
intc;
bytebuf[]=newbyte[1];
while((c=rr.read(pos))!
=-1){
pos++;
buf[0]=(byte)c;
System.out.write(buf,0,1);
rr.close();
压缩的性能开销
Java提供用于压缩和解压字节流的类,这些类包含在java.util.zip包里面,这些类也作为Jar文件的服务基础(Jar文件是带有附加文件列表的Zip文件)。
压缩的目的是减少存储空间,同时被压缩的文件在IO速度不变的情况下会减少传输时间。
压缩时候要消耗CPU时间,占用内存。
压缩时间=数据量/压缩速度。
IO传输时间=数据容量/IO速度。
传输数据的总时间=压缩时间+I/O传输时间
压缩是提高还是损害I/O性能很大程度依赖你的硬件配置,特别是和处理器和磁盘驱动器的速度相关。
使用Zip技术的压缩通常意味着在数据大小上减少50%,但是代价是压缩和解压的时间。
一个巨大(5到10MB)的压缩文本文件,使用带有IDE硬盘驱动器的300-MHzPentiumPC从硬盘上读取可以比不压缩少用大约1/3的时间。
压缩的一个有用的范例是向非常慢的媒介例如软盘写数据。
使用高速处理器(300MHzPentium)和低速软驱(PC上的普通软驱)的一个测试显示压缩一个巨大的文本文件然后在写入软盘比直接写入软盘快大约50%。
下面的程序接收一个输入文件并将之写入一个只有一项的压缩的Zip文件:
importjava.util.zip.*;
publicclasscompress{
publicstaticvoiddoit(Stringfilein,Stringfileout){
FileInputStreamfis=null;
FileOutputStreamfos=null;
fis=newFileInputStream(filein);
fos=newFileOutputStream(fileout);
ZipOutputStreamzos=
newZipOutputStream(fos);
ZipEntryze=newZipEntry(filein);
zos.putNextEntry(ze);
finalintBUFSIZ=4096;
byteinbuf[]=newbyte[BUFSIZ];
while((n=fis.read(inbuf))!
=-1)
zos.write(inbuf,0,n);
fis=null;
zos
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- IO 性能 分析