来源:网络 | 2007-4-19 | (有3785人读过)
所有的程序语言都提?copy;与本机文件系统交互的方式;Java也不例外。我们将看看Java是怎样处理标准文件输入输出的(包括stdin,stout,stderr)。当你在网络上开发小程序时,你必须注意直接文件输入输出是不安全因素的关键。大多数用户设置他们的浏览器,可让你自由的访问他们的文件系统,但有?copy;不让你访问。当然,如果你开发你内部的应用程序,你也许需要直接访问文件。
标准输入输出Unix的用户,或其他基于命令行系统的用户(如DOS),都知道标准输入输出的含义。标准输入文件是键盘,标准输出文件是你的终端屏幕。标准错误输出文件也指向屏幕,如果有必要,它也可以指向另一个文件以便和正常输出区分。
系统类Java通过系统类达到访问标准输入输出的功能。上面提到的三个文件在这个系统类中实现:StdinSystem.in作为InputStream类的一个实例来实现stdin,你可以使用read()和skip(longn)两个成员函数。read()让你从输入中读一个字节,skip(longn)让你在输入中跳过n个字节。
StoutSystem.out作为PrintStream来实现stdout,你可以使用print()和println()两个成员函数。这两个函数支持Java的任意基本类型作为参数。
StderrSystem.err同stdout一样实现stderr。象System.out一样,你可以访问PrintStream成员函数。
9.2标准输入输出例子 这里有一个例子,功能象Unix里的cat或type:
importjava.io.*classmyCat{publicvoidmain(Stringargs[])throwsIOException{intb;intcount=0;while((b=System.in.read())!=-1){count++;System.out.print((char)b);}System.out.println();//blanklineSystem.err.println("counted"+count+"totalbytes.");}}
9.3普通输入输出类 除了基本的键盘输入和屏幕输出外,我们还需要联系文件的输入输出。我们将学习下面几个类:lFileInputStreamlDataInputStreamlFileOutputStreamlDataOutputStream
作为参考,再列出一?copy;特定应用的类:lPipedInputStreamlBufferedInputStreamlPushBackInputStreamlStreamTokenizerlPipedOutputStreamlBufferedOutputStreamlRandomAccessFile
我们不在此讨论这?copy;类,但你可以在JAVA_HOME/src/java/io目录里查看每个类的成员函数定义。
9.4文件 在我们进行文件操作时,需要知道一?copy;关于文件?信息。File类提?copy;了一?copy;成员函数来操纵文件和获得一?copy;文件的信息。
9.4.1创建一个新的文件对象 你可用下面三个方法来创建一个新文件对象:
FilemyFile;myFile=newFile("etc/motd");
或
myFile=newFile("/etc","motd");//moreusefulifthedirectoryorfilenamearevariables
或
FilemyDir=newfile("/etc");myFile=newFile(myDir,"motd");
这三种方法取决于你访问文件的方式。例如,如果你在应用程序里只用一个文件,第一种创建文件的结构是最容易的。但如果你在同一目录里打开数个文件,则第二种或第三种结构更好一?copy;。
9.4.2文件测试和使用 一?copy;你创建了一个文件对象,你便可以使用以下成员函数来获得文件相关信息:
文件名lStringgetName()lStringgetPath()lStringgetAbslutePath()lStringgetParent()lbooleanrenameTo(FilenewName)
文件测试lbooleanexists()lbooleancanWrite()lbooleancanRead()lbooleanisFile()lbooleanisDirectory()lbooleanisAbsolute()
一般文件信息llonglastModified()llonglength()
目录用法lbooleanmkdir()lString[]list()
9.4.3文件信息获取例子程序 这里是一个独立的显示文件的基本信息的程序,文件通过命令行参数传输:
importjava.io.*;classfileInfo{FilefileToCheck;publicstaticvoidmain(Stringargs[])throwsIOException{if(args.length>0){for(inti=0;i<args.length;i++){fileToCheck=newFile(args[i]);info(fileToCheck);}}else{System.out.println("Nofilegiven.");}}publicvoidinfo(Filef)throwsIOException{System.out.println("Name:"+f.getName());System.out.println("Path:"=f.getPath());if(f.exists()){System.out.println("Fileexists.");System.out.print((f.canRead()?"andisReadable":""));System.out.print((f.cnaWrite()?"andisWriteable":""));System.out.println(".");System.out.println("Fileis"+f.lenght()="bytes.");}else{System.out.println("Filedoesnotexist.");}}}
9.5输入流 InputStreamSequenceInputStreamFileInputStreamPipedInputStreamByteArrayInputStreamFileterInputStreamStringBufferInputStream
DataInputStreamLineNumberInputStreamPushbackInputStreamBufferedInputStream有好几个类是专门用来处理文件输入的。下面是文件输入类的层次结构:
9.5.1FileInputStream对象 FileInputStream典型地表示一种顺序访问的文本文件。通过使用FileInputStream你可以访问文件的一个字节、几个字节或整个文件。
9.5.2打开FileInputStream 为一个文件打开输入流FileInputStream,你必须将文件名或文件对象传送给结构:
FileInputStreammyFileStream;myFileStream=newFileInputStream("/etc/motd");
你还可以象下边这样从FileInputStream里读文件信息:
FilemyFile;FileInputSteammyFileStream;myFile=newFile("/etc/motd");myFileStream=newFileInputStream(myFile);
一?copy;FileInputStream输入流打开,你就可以从里面读取信息了。read()成员函数有以下几种选项:
lintread()//readsonebyte//return-1atendofstreamlintread(byteb[])//fillsentirearray,ifpossible//returnsnumberofbytesread//returns-1ifendofstreamisreached
lintread(byteb[],intoffset,intlen)//readslenbytesintobstartingatb[offset]//Returnsnumberofbytesread,//or-1ifendofstreamisreached.
9.5.3关闭FileInputStream 当你完成一个文件的操作,你可选两种方法关闭它:显式关闭和隐式关闭,隐式关闭是自动垃圾回收时的功能。
显式关闭如下:myFileStream.close();
9.6例程:显示一个文件 如果文件的访问权限足够,你可以在TextArea对象里显示文件内容。
下面是显示文件的程序片断:
FileInputStreamfis;TextAreata;publicvodinit(){byteb[]=newbyte[1024];intI;//makeitbigenoughorwaituntilyou//knowthesizeofthefileStrings;try{fis=newFileInputStream("/etc/motd");}catch(FileNotFoundExceptione){/*dosomethingappropriate*/}try{I=fis.read(b);}catch(IOExceptione){/*dosomethingappropriate*/}s=newString(b,0);ta=newTextArea(s,5,40);add(ta);}
9.7DataInputStreams DataInputStreams与FileInputStreams差不多。Data流可以直接读任意一种变量类型,如浮点数,整数和字符等。一般来说,对二进制文件使用DataInputStream流。
9.7.1打开和关闭DataInputStreams 打开和关闭DataInputStreams对象时,其方法与FileInputStreams相同:
DataInputStreamsmyDataStream;FileInputStreamsmyFileStream;
//getafilehandlemyFileStream=newFileInputStream("/usr/db/stock.dbf");//open,or"chain"adatainputfilemyDataStream=newDataOutputStream(myFileStream);
//Nowwecanusebothinputstreamstoaccessourfile//j(Ifwewantto...)myFileStream.read(b);I=myDataStrea.readInt();
//closethedatafrielexplicityly//Alwaysclosethe"topmost"filestreammyDataStream.close();myFileStream.close();
9.7.2读DataInputStreams 当你从DataInputStreams流里访问文件时,你可以使用与FileInputStream流相同的成员函数read()。但你也可以使用其他访问方法来读取不同种类的数据:
lbytereadByte()lintreadUnsignedByte()lshortreadShort()lintreadUnsighedShort()lcharreadChar()lintreadIntllongreadLong()lfloatreadFloat()ldoublereadDouble()lStringreadLine()
以上每一个成员函数都读取相应的数据对象。象StringreadLine()成员函数,你可使用\n,\r,\r\n,或EOF作为字符?reg;结束符。
读一个长整型,例如:
longserialNo;...serialNo=myDataStream.readLong();
9.8URL输入流 除了基本文件访问外,Java还提?copy;了通过网络使用URL访问对象的功能。在下面这个例子里,我们用getDocumentBase()成员函数并显式指定URL对象来访问声音和图象。
StringimageFile=newString("images/Duke/T1.gif");images[0]=getImage(getDocumentBase(),imageFile();
如果我们愿意,可以直接使用URL:URLimageSource;imageSource=newURL("http://555-1212.com/~info");images[0]=getImage(imageSource,"Duke/T1.gif");
我们可以为相应的URL打开输入流。例如,下面的程序里包括一个数据文件:InputStreamis;bytebuffer[]=newbyte[24];is=newURL(getDocumentBase(),dataname).openStream();
现在我们可以使用is,就象使用FileInputStream对象一样:is.read(buffer.0,buffer.length);
注意:有?copy;用户设置了他们的浏览器安全属性,可以不让你的程序访问他们的文件。
9.9OutputStreams 上面我们谈到了读数据,那么如何实现写数据呢?象输入流一样,输出流也有类似的层次结构:
OutputStream
FileOutputStreamPipedOutputStreamByteArrayOutputStreamFilterOutputStream
DataOutputStreamPrintStreamBufferedOutputStream
我们将分析FileOutputStream和DataOutputStream类来完成我们碰到的输出流问题。其它的输出流包含了更多的信息和成员函数。象输入流的源文件一样,这?copy;文件在$JAVA_HOME/src/java/io目录下。
9.9.1FileOutputStream类 FileOutputStream对象用于向一个文本文件写数据。象输入文件一样,你得先打开这个文件后才能写这个文件。
9.9.2打开一个FileOutputStream对象 要打开一个FileOutputStream对象,象打开一个输入流一样,你可以将字符?reg;或文件对象作为参数:FileOutputStreammyFileStream;myFileStream=newFileOutputStream("/etc/motd");
象输入流一样,你也可这样使用:FilemyFile;FileOutputStreammyFileStream;myFile=newFile("/etc/motd");myFileStream=newFileOutputStream(myFile);
9.9.3写入一个流 一?copy;文件被打开,你便可以使用write()函数向文件里写一?copy;数据。就象输入流的read()函数一样,你可有三种方法:lvoidwrite(intb);//writesoutonebytelvoidwrite(byteb[]);//writesoutentirearraylvoidwrite(byteb[],intoffset,intlength);//writeoutlengthbytesofb[],startingatb[offset]
9.9.4关闭一个FileOutputStream对象 关闭输出流和关闭输入流方法一样,你可以使用显式方法:myFileStream.close();你也可以让系统自动关闭它。
9.10例子:存储信息 下面有一个程序,让用户输入一?copy;姓名和电话号码。每一个姓名和号码将加在文件里。用户通过点“Done"按钮来告诉系统整个列表已输入完毕。
一?copy;用户输入完整个列表,程序将创建一个输出文件并显示或打印出来。例如:
555-1212,Tom123-456-7890,PeggyL.234-5678,Marc234-5678,Ron876-4321,Beth&Brian33.1.42.45.70,Jean-Marc
下面是程序的源代码:importjava.io.*;
//Phones.java//Asimpledatabasecreationprogram
classPhones{staticFileOutputStreamfos;publicstaticfinalintlineLength=81;publicstaticvoidmain(Stringargs[])throwsIOExciption{byte[]phone=newbyte[lineLength];byte[]name=newbyte[lineLenght];intI;fos=newFileOutputStream("phone.numbers");while(true){System.err.println("Enteraname(enter’done’toquit)");readLine(name);if("done".equalsIgnoreCase(newString(name,0,0,4))){break;}System.err.println("Enterthephonenumber");readLine(phone);for(i=0;phone[i]!=0;i++){fos.write(phone[i]);}fos.write(’,’);for(i=0;name[i]!=0;I++){fos.write(name[i]);}fos.write(’\n’);}fos.close();}
privatestaticvoidreadLine(byteline[])throwsIOException{inti=0,b=0;
while((i<lineLengh-1))&&((b=System.ini.read())!=’\n’)){line[i++]=(byte)b;}line[i]=(byte)0;}}
9.11BufferedOutput流 如果你处理的数据量很多,或向文件写很多次小数据,你可以使用一个BufferedOutput流。BufferedOutput流提?copy;和FileOutputStream类同样的写操作方法,但所有输出全部存放在一个缓冲区里。当你填满缓冲区,它将一次性写入磁盘。或者你主动将缓冲区写入磁盘。
9.11.1创建BufferedOutput流 如果要创建一个BufferedOutput流,首先需要一个FileOutput流。然后将缓冲区链接到FileOutput流:FileOutputStreammyFileStream;BufferedOutputStreammyBufferStream;//getafilehandlemyFileStream=newFileOutputStream("/usr/db/stock.dbf");//chainabufferedoutputstreammyBufferSSstream=newBufferedOutputStream(myFileStream);
9.11.2更新和关闭BufferedOutput流 和普通FileOutput流一样,向BufferedOutput流里的每一次写操作和写入磁盘操作并不是一一对应的。要想在程序结束?reg;前将缓冲区里的数据写入磁盘,除非填满缓冲区,否则只有显式调用flush()函数://forceleft-overdatatodiskmyBufferStream.flush();//closethedatafileexplicitly//Alwaysclosethe"topmost"filestreammyBufferStream.close();myFileStream.close();
9.12DataOutput流 和DataInputStream对应,Java还提?copy;了DataOutput流。使用DataOutput流,我们可以向文件写入二进制数据。
9.12.1打开和关闭DataOutput流对象 打开和关闭DataOutput流对象与打开、关闭FileOutput流对象方法一样:DataOutputStreammyDataStream;FileOutputStreammyFileStream;BufferedOutputStreammyBufferStream;
//getafilehandlemhyFileStream=newFileOutputStream("/usr/db/stock.dbf");//chainabufferedoutputstream(forefficiency);myBufferStream=newBufferedOutputStream(myFileStream);//chainadataoutputfilemyDataStream=newDataOutputStream(myBufferStream);
//Nowwecanusebothinputstreamstoaccessourfile//(iiIfwewantto...)myBufferStream.write(b);myDataStream.writeInt(i);
//closethedatafileexplicitly//Alwayscolsethe"topmost"filestreammyDataStream.close();myBuffersStream.close();myFileStream.close();
9.12.2向DataOutput流写数据 FileOutput流里的write()函数各种方法都适用于DataOutput流。你还可以看到DataInput流的类似函数方法:lvoidwriteBoolean(booleanv)lvoidwriteByte(intv)lvoidwriteShort(intv)lvoidwriteChar(intv)lvoidwriteInt(intv)lvoidwriteFloat(floatv)lvoidwriteDouble(doublev)lvoidwriteBytes(strings)lvoidwriteChars(strings)
对字符?reg;来说,有两种选择:byte和char。记住byte是8位数据而char是16位数据。如果你想利用Unicode字符的优点,你应使用writeChars()函数。
9.12.3输出记数 在使用二进制数据输出时常用的另外一个函数是size()。这个函数返回写入文件数据的总字节数。你也可用size()函数将数据文件分成四字节为单位的块,例如:...intbytesLeft=myDataStream.size()%4;for(intI=0;I<bytesLeft;I++){myDataStrea.write(0);}...
9.13随机访问文件 我们读文件常常不是从头至尾顺序读的。你也许想将一文本文件当作一个数据库,读完一个记录后,跳到另一个记录,它们在文件的不同地方。Java提?copy;了RandomAccessFile类让你操作这种类型的输入输出。
9.13.1创建随机访问文件 打开随机访问文件有两种方法:l用文件名myRAFile=newRandomAccessFile(Stringname,Stringmode);l用文件对象myRAFile=newRandomAccessFile(Filefile,Stringmode);
mode参数决定了访问文件的权限,如只读’r’或读写’wr’等。
例如,我们打开一个数据库更新数据:RandomAccessFilemyRAFile;myRAFile=newRandomAccessFile("/usr/db/stock.dbf","rw");
9.13.2访问信息 RandomAccessFile对象的读写操作和DataInput/DataOutput对象的操作方式一样。你可以使用在DataInputStream和DataOutputStream里出现的所有read()和write()函数。
还有几个函数帮助你在文件里移动指针:llonggetFilePointer();返回当前指针lvoidseek(longpos);将文件指针定位到一个绝对地址。地址是相对于文件头的偏移量。地址0表示文件的开头。llonglength();返回文件的长度。地址"length()"表示文件的结尾。
9.13.3增加信息 你可以使用随机访问文件来设置成增加信息模式:myRAFile=newRandomAccessFile("/tmp/java.log","rw");myRAFile.seek(myRAFile.length());//Anysubsequentwrite()swillbeappendedtothefile
9.13.4追加信息例子 下面是一个在已存在文件后面追加字符?reg;的例子:importjava.io.IOException;importjava.io.RandomAccessFile;
classraTest{publicstaticvoidmain(Stringargs[])throwsIOException{RandomAccessFilemyFAFile;Strings="InformationtoAppend\nHimom!\n";//openourrandomaccessfilemyRAFile=newRandomAccessFile("/tmp/java.log","rw");//movetotheendofthefilemyRAFile.seek(myRAFile.length());//Startappending!myRAFile.writeBytes(s);
myRAFile.close();}}
|