if(buf[i]=='\n')
cnt++;
}
System.out.println(cnt);
}
catch(IOExceptione){
System.err.println(e);
}
}
}
这个方法很方便,在这里文件被当作一个字节数组。
但是有一个明显得问题是有可能没有读取一个巨大的文件的足够的内存。
缓冲的另一个方面是向窗口终端的文本输出。
缺省情况下,System.out(一个PrintStream)是行缓冲的,这意味着在遇到一个新行符后输出缓冲区被提交。
格式化的代价
实际上向文件写数据只是输出代价的一部分。
另一个可观的代价是数据格式化。
考虑下面的字符输出程序
性能对比结果为:
这些程序产生同样的输出。
运行时间是:
格式化方法
示例语句
运行时间
简单的输出一个固定字符
System.out.print(s);
1.3秒
使用简单格式"+"
Strings=字符+字符,
System.out.print(s);
1.8秒
使用java.text包中的MessageFormat类的对象方法
Strings=fmt.format(values);
System.out.print(s);
7.8秒
使用java.text包中的MessageFormat类的静态方法
7.8*1.3秒
最慢的和最快的大约是6比1。
如果格式没有预编译第三种方法将更慢,使用静态的方法代替:
第三个方法比前两种方法慢很多的事实并不意味着你不应该使用它,而是你要意识到时间上的开销。
在国际化的情况下信息格式化是很重要的,关心这个问题的应用程序通常从一个绑定的资源中读取格式然后使用它。
方法1,简单的输出一个固定的字符串,了解固有的I/O开销:
publicclassformat1{
publicstaticvoidmain(Stringargs[]){
finalintCOUNT=25000;
for(inti=1;i<=COUNT;i++){
Strings="Thesquareof5is25\n";
System.out.print(s);
}
}
}
方法2,使用简单格式"+":
publicclassformat2{
publicstaticvoidmain(Stringargs[]){
intn=5;
finalintCOUNT=25000;
for(inti=1;i<=COUNT;i++){
Strings="Thesquareof"+n+"is"+
n*n+"\n";
System.out.print(s);
}
}
}
方法3,第三种方法使用java.text包中的MessageFormat类的对象方法:
importjava.text.*;
publicclassformat3{
publicstaticvoidmain(Stringargs[]){
MessageFormatfmt=
newMessageFormat("Thesquareof{0}is{1}\n");
Objectvalues[]=newObject[2];
intn=5;
values[0]=newInteger(n);
values[1]=newInteger(n*n);
finalintCOUNT=25000;
for(inti=1;i<=COUNT;i++){
Strings=fmt.format(values);
System.out.print(s);
}
}
}
方法4,使用MessageFormat.format(String,Object[])类的静态方法
importjava.text.*;
publicclassformat4{
publicstaticvoidmain(Stringargs[]){
Stringfmt="Thesquareof{0}is{1}\n";
Objectvalues[]=newObject[2];
intn=5;
values[0]=newInteger(n);
values[1]=newInteger(n*n);
finalintCOUNT=25000;
for(inti=1;i<=COUNT;i++){
Strings=
MessageFormat.format(fmt,values);
System.out.print(s);
}
}
}
这比前一个例子多花费1/3的时间。
随机访问的性能开销
RandomAccessFile是一个进行随机文件I/O(在字节层次上)的类。
这个类提供一个seek方法,和C/C++中的相似,移动文件指针到任意的位置,然后从那个位置字节可以被读取或写入。
seek方法访问底层的运行时系统因此往往是消耗巨大的。
一个更好的代替是在RandomAccessFile上建立你自己的缓冲,并实现一个直接的字节read方法。
read方法的参数是字节偏移量(>=0)。
这样的一个例子是:
这个程序简单的读取字节序列然后输出它们。
适用的情况:
如果有访问位置,这个技术是很有用的,文件中的附近字节几乎在同时被读取。
例如,如果你在一个排序的文件上实现二分法查找,这个方法可能很有用。
不适用的情况:
如果你在一个巨大的文件上的任意点做随机访问的话就没有太大价值。
importjava.io.*;
publicclassReadRandom{
privatestaticfinalintDEFAULT_BUFSIZE=4096;
privateRandomAccessFileraf;
privatebyteinbuf[];
privatelongstartpos=-1;
privatelongendpos=-1;
privateintbufsize;
publicReadRandom(Stringname)
throwsFileNotFoundException{
this(name,DEFAULT_BUFSIZE);
}
publicReadRandom(Stringname,intb)
throwsFileNotFoundException{
raf=newRandomAccessFile(name,"r");
bufsize=b;
inbuf=newbyte[bufsize];
}
publicintread(longpos){
if(posendpos){
longblockstart=(pos/bufsize)*bufsize;
intn;
try{
raf.seek(blockstart);
n=raf.read(inbuf);
}
catch(IOExceptione){
return-1;
}
startpos=blockstart;
endpos=blockstart+n-1;
if(posendpos)
return-1;
}
returninbuf[(int)(pos-startpos)]&0xffff;
}
publicvoidclose()throwsIOException{
raf.close();
}
publicstaticvoidmain(Stringargs[]){
if(args.length!
=1){
System.err.println("missingfilename");
System.exit
(1);
}
try{
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();
}
catch(IOExceptione){
System.err.println(e);
}
}
}
压缩的性能开销
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.io.*;
importjava.util.zip.*;
publicclasscompress{
publicstaticvoiddoit(Stringfilein,Stringfileout){
FileInputStreamfis=null;
FileOutputStreamfos=null;
try{
fis=newFileInputStream(filein);
fos=newFileOutputStream(fileout);
ZipOutputStreamzos= newZipOutputStream(fos);
ZipEntryze=newZipEntry(filein);
zos.putNextEntry(ze);
finalintBUFSIZ=4096;
byteinbuf[]=newbyte[BUFSIZ];
intn;
while((n=fis.read(inbuf))!
=-1)
zos.write(inbuf,0,n);
fis.close();
fis=null;
zos