下载

1下载券

加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 第09章 Java的IO系统

第09章 Java的IO系统.pdf

第09章 Java的IO系统

slyang11111
2012-11-21 0人阅读 举报 0 0 0 暂无简介

简介:本文档为《第09章 Java的IO系统pdf》,可适用于IT/计算机领域

第章Java的IO系统教学目标:本章介绍Java语言中的IO系统。IO系统是用户和磁盘文件或者网络文件交互的接口本章主要介绍了Java语言中IO流的体系结构重点说明了Java字节流API的使用方法包括文件流、管道流和各种各样的过滤器流。本章还介绍了File类和AccessFile类的使用。最后本章介绍了Java版本才引入的新IO系统NIO详尽的说明了NIO中缓存、字符集、通道和选择器的概念和使用方法。教学重点与难点:◆JavaIO流的体系结构◆字符流的文件流和字节流的文件流◆字节流的过滤器流的种类和使用方法◆对象序列化‹File类的使用‹NIO的体系结构‹NIO的缓存(Buffer)和通道(Channel)Java的IO系统概述Java的IO系统包括传统的流IO以及JavaSDK版本引进的NIO系统。本节所介绍的是Java的传统流IONIO在本章另有专门介绍。流的概念流是一种抽象的发送和接受数据的方法。当处理一个流时只需要把精力集中在流的两个端点:从一个流中读取数据或是向一个流中发送数据时的起始位置而不需要考虑这个流的另一端是什么数据是如何传送到这个流的另一端的甚至当一个流到达时它是什么样的格式。流使应用程序有相当大的灵活性流允许程序与内存控制台甚至是一个网络连接之间进行读写操作就好像那个网络连接只是一个简单的磁盘文件。JavaIO系统介绍Java提供了许多不同形式的流以适应各种不同的环境。Java的IO库提供了四个抽象类:InputStream、OutputStream、Reader和Writer。InputStream和OutputStream用于处理面向字节的流它们读写的最小单位是个字节(Byte)Reader和Writer用于处理面向字符的流它们读写的最小单位是个字节因为在Java中字符是以Unicode编码存储的而一个Unicode码占用个字节。InputStream和Reader处理输入OutputStream和Writer处理输出。Reader和Writer、InputStream和OutputStream有很多继承的子类本章将详细介绍其中最常用的一些类面向字节的流将是本章的重点。字符流API面向字符流的类都继承自Reader和Writer。抽象类Reader的子类有BufferedReader、CharArrayReader、FilterReader、InputStreamReader、PipedReader和StringReader。其中FilterReader类是抽象类。BufferedReader类有子类LineNumberReaderFilterReader有子类PushbackReaderInputStreamReader类有子类FileReader。InputStreamReader是字节流到字符流的桥梁。它读取流的字节并将之以一定的字符集编码成为字符。字节流API面向字节流的类都继承自InputStream和OutputStream。其中InputStream用于读操作OutputStream用于写操作。在JavaSDK中InputStream的子类有:AudioInputStream、ByteArrayInputStream、FileInputStream、FilterInputStream、InputStream、ObjectInputStream、PipedInputStream、SequenceInputStream、StringBufferInputStream。而OutputStream的子类有:ByteArrayOutputStream、FileOutputStream、FilterOutputStream、ObjectOutputStream、OutputStream、PipedOutputStream。字符流如前所述Java的IO流可分为字符流和字节流。字符流面向字符读写的单位是字节。Java的字符流包括文件流、管道流、字符串流等。本小节介绍文件流和管道流。文件流FileReader和FileWriter用于文件字符流的读写操作。FileReader和FileWriter接受File或FileDescriptor或String类的对象作为构造函数的参数用于指明要操作的文件。如:FileReaderin=newFileReader(inpile)FileWriterout=newFileWriter(outpile)得到FileReader和FileWriter对象后就可以分别调用read()方法和write()方法机你姓读写。下面的程序实现了从复制一个文本文件的功能。importjavaio*publicclasstxtCopy{publicstaticvoidmain(Stringargs)throwsIOException{if(argslength<)returnFileinpile=newFile(args)Fileoutpile=newFile(args)FileReaderin=newFileReader(inpile)FileWriterout=newFileWriter(outpile)intcwhile((c=inread())!=)outwrite(c)inclose()outclose()}}管道流管道(pipe)流是一种特殊的流。用于在不同线程(threads)间直接传送数据。一个线程发送数据到输出管道另一个线程从输入管道中读数据。通过使用管道实现不同线程间的通讯。Java提供两个类来处理面向字符的管道:PipedReader和PipedWriter。PipedReader类继承自Reader抽象类而PipedWriter类继承自Writer抽象类。PipedReader用于从管道中读取数据而PipedWriter用于写入数据。利用PipedReader类和PipedWriter类建立面向字符流的管道方法如下:PipedReaderx=newPipedReader()PipedWritery=newPipedWriter(x)或者:PipedWritery=newPipedWriter()PipedReaderx=newPipedReader(y)这样就可以通过ywrite()把数据写入管道通过xread()读取管道的数据。PipedReader类和PipedWriter类还提供一个方法connect()用于连接管道。例如:PipedReaderx=newPipedReader()PipedWritery=newPipedWriter()yconnect(x)这和上面两个例子的效果是一样的。下面这个简单的例子说明了字符管道流的使用方法。这个简单的例子是很不完善的如果str很大的话管道将面临缓冲被耗光的情况。这样的情况下writerwrite()将阻塞。importjavaio*publicclasstxtPipe{staticpublicvoidmain(Stringargs)throwsIOException{PipedWriterwriter=newPipedWriter()PipedReaderreader=newPipedReader()writerconnect(reader)Systemoutprintln("Readytoread"readerready())Stringstr="Hello,World!"for(inti=i<strlength()i){writerwrite((char)strcharAt(i))}writerclose()Systemoutprintln("Readytoread"readerready())intchwhile((ch=readerread())!=){Systemoutprintln((char)ch)}readerclose()}}字节流字节流是Java中面向字节的流它的读写对象是字节。字节流是本章的重点。本章所介绍的字节IO流包括文件流、管道流以及名目繁多的过滤器流。文件流FileInputStream和FileOutputStream用于文件字节流的读写。和字符文件流类似FileInputStream和FileOutputStream接受File或FileDescriptor或String类的对象作为构造函数的参数用于指明要操作的文件。如:FileInputStreamin=newFileInputStream(inpile)FileOutputStreamout=newFileOutputStream(outpile)FileInputStream的read()方法和FileOutputStream的write()方法用于文件流的读写。下面的程序实现文件的复制。importjavaio*publicclassbyteCopy{publicstaticvoidmain(Stringargs)throwsIOException{if(argslength<)returnFileinpile=newFile(args)Fileoutpile=newFile(args)FileInputStreamin=newFileInputStream(inpile)FileOutputStreamout=newFileOutputStream(outpile)intcwhile((c=inread())!=)outwrite(c)inclose()outclose()}}管道流在字节流中也有管道流的实现。PipedInputStream和PipedOutputStream分别用于字节流管道流的读和写。在上面小节中我们实现了字符流的管道流读写的一个小程序下面我们改写这个程序让它适用于字节流。importjavaio*publicclassbytePipe{staticpublicvoidmain(Stringargs)throwsIOException{PipedOutputStreampout=newPipedOutputStream()PipedInputStreampin=newPipedInputStream()poutconnect(pin)for(inti=i<i){poutwrite(i)}poutclose()intiwhile((i=pinread())!=){Systemoutprintln(i)}pinclose()}}过滤器流过滤器流基于其他信息流允许信息流通过并且提供额外的功能。例如一个信息摘要流的构造如下:FileInputStreamin=newFileInputStream(fileName)MessageDigestmd=MessageDigestgetInstance("MD")DigestInputStreamdos=newDigestInputStream(in,md)DigestInputStream利用FileInputStream对象in和MessageDigest对象md作为构造函数的参数当DigestInputStream对象dos调用read()方法时md内容得到更新最后可从md中得到所读入信息流的MD摘要信息。缓冲流有时候需要处理的数据量特别多或者需要多次从设备读取或者写入小的数据。为了避免频繁访问输出输入设备所带来的性能下降Java提供了BufferedInputStream和BufferedOutputStream。BufferedInputStream一次性从输出输入设备中读入很多数据存放在缓冲区中read()等操作将从缓冲区中读取数据。BufferedOutputStream则把write()等方法写入的数据暂时存放在缓冲区中当缓冲区满或者用户调用flush()强制写入数据时才把数据写入输出输入设备。这样的机制能够有效的减少读写设备的次数从而提高系统的性能。下面这个程序利用BufferedInputStream和BufferedOutputStream实现了下载网络文件的功能。BufferedInputStream的利用可以避免从网络上多次读取文件从而提高了IO的速度。importjavanet*importjavaio*publicclassDownLoad{staticvoidgetUrlFile(StringurlString){BufferedInputStreamin=BufferedOutputStreamout=intctry{URLurl=newURL(urlString)Filefile=newFile(urlgetFile())Stringfilename=filegetName()intsize=in=newBufferedInputStream(urlopenStream())out=newBufferedOutputStream(newFileOutputStream(""urlgetFile()))Systemoutprintln("Downloading"urlgetFile())while((c=inread())!=){outwrite(c)size}inclose()outclose()Systemoutprintln(size"bytesdownloaded")}catch(IOExceptione){eprintStackTrace()}}publicstaticvoidmain(Stringargs){StringurlString=argsgetUrlFile(urlString)}}流校验CheckedInputStream类和CheckedOutputStream类在读写数据时维护着数据的一个Checksum值这个值可以用来检验数据的完整性。CheckedInputStream类和CheckedOutputStream类的用法如下所述:ChecksumCK=newCheckSum()CheckedOutputStreamCOS=newCheckedOutputStream(CK,Fptr)COSwrite(x)和:CheckSumCK=newCheckSumCheckedInputStreamCIS=newCheckInputStream(CK,Fptr)x=CISread()if(CK!=oldCK){throwsomeerror}加密流加密是一个将欲加密的数据用一些数学运算转成一团令人看不懂的东西的过程解密则是将加密文转换回原始文字的过程。这个过程中扮演原始文字与加密文字之间转换的数学算法称为加密(Cipher)。现代的Cipher多半会用密钥(Key)来加密与解密资料。所谓密钥是指一个机密值我们可将它视为一通行密码。加密文字必需使用对映的密钥才能解密为原始文字。对称型加密在传送端与接收端所用的密钥是一样的对称型密钥又叫私钥加密(PrivateKeyCipher)因为密钥的值只有传送端和接收端知道。如果有第三者知道了私钥值也就能解开加密的资料。非对称型的加密又叫公钥加密(PublicKeyCipher)Cipher除了私钥(PrivateKey)外还会引进一可以随意散发的公钥(PublicKey)。被公钥加密的数据只有相对映的私钥才可以解开同样的被私钥加密的数据也只有相对映的公钥可以解开。信息摘要是从一组输入数据计算所得的一个特别数字其原理运作和哈希函数类似。在密码学的运用里一般是用来验证数据是否被篡改。Java提供了用于信息加密的过滤流CipherInputStream和CipherOutputStream。CipherInputStream和CipherOutputStream类所用的加密及解密算法都是封装在一个cipher对象里。对称密钥方式需使用同一个密钥才可以加密及解密而非对称必要方式加密时需要用一个为大众所知道的公钥但必须要有一个秘密保存的密钥才可以解密。要建立密文流必须把一个cipher对象传给对应的构造函数并要指定输出或输入流如:publicCipherInputStream(InputStreamin,Cipherc)PublicCipherOutputStream(OutputStreamout,Cipherc)下面的程序可以对一个文件进行DES加密DES是对称密钥的加密方法运行这个程序时必须给出密钥。importjavaio*importjavasecurity*importjavaxcrypto*publicclassPwdDES{publicstaticfinalintkBufferSize=publicstaticvoidmain(Stringargs)throwsException{if(argslength<){Systemoutprintln("Usage:PwdDESe|dpasswdinpileoutpile")return}读取密钥KeykeyKeyGeneratorgenerator=KeyGeneratorgetInstance("DES")generatorinit(newSecureRandom(argsgetBytes()))key=generatorgenerateKey()创建Cipher实例Ciphercipher=CiphergetInstance("DES")加密或解密if(argsindexOf("e")!=)cipherinit(CipherENCRYPTMODE,key)elsecipherinit(CipherDECRYPTMODE,key)FileInputStreamin=newFileInputStream(args)FileOutputStreamfileOut=newFileOutputStream(args)CipherOutputStreamout=newCipherOutputStream(fileOut,cipher)bytebuffer=newbytekBufferSizeintlengthwhile((length=inread(buffer))!=)outwrite(buffer,,length)inclose()outclose()}}信息摘要javautilsecurity提供两种能为信息流计算信息摘要(messagedigest)的过滤器流:DigestInputStream和DigestOutputStream。信息摘要以javautilsecurityMessageDigest类表示是能用来辨识流得一种强哈希码(stronghashcode)。我们可从任何长度的信息流计算它的信息摘要而无法从信息摘要中得到任何有关这个信息流的信息。信息摘要可当作是电子签名(digitalsignature)或者检测通过网络传输的数据是否遭到损毁。下面是一个计算文件的MD摘要的程序。这个程序打开参数所指定的文件创建一个DigestInputStream类的实例dos调用dosread()则更新与其关联的MessageDigest类的实例md。最后由mddigest()返回其MD摘要。importjavaio*importjavasecurity*publicclassMD{publicstaticvoidmain(Stringargs)throwsException{bytedigest=getMDDigest(args)Systemoutprintln("MD("args")="toHexString(digest))}staticbytegetMDDigest(StringfileName)throwsIOException,NoSuchAlgorithmException{FileInputStreamin=newFileInputStream(fileName)MessageDigestmd=MessageDigestgetInstance("MD")DigestInputStreamdos=newDigestInputStream(in,md)while(dosread()!=)bytedigest=mddigest()dosclose()inclose()returndigest}publicstaticStringtoHexString(byteb){StringBufferhexString=newStringBuffer()StringplainTextfor(inti=i<blengthi){plainText=IntegertoHexString(xFFbi)if(plainTextlength()<){plainText=""plainText}hexStringappend(plainText)}returnhexStringtoString()}}运行这个程序的结果如下:E:WorkJAVAJavaCodeChap>javaMDMDjavaMD(MDjava)=dbcddededdbfdcd压缩流Java还提供了用于压缩或解压缩信息流的过滤器流它们是DeflaterInputStream(DeflaterOutputStream)、GZIPInputStream(GZIPOutputStream)、ZipInputStream(ZipOutputStream)、JarInputStream(JarOutputStream)分别用于处理“deflater”、Gzip、Zip和Jar类型的压缩流。压缩流处理的对象不限于文件任何信息流均可以应用压缩流。应用程序可以利用它们来压缩或者解压缩网络的信息数据。压缩或解压缩的过程虽然耗费一些CPU时间,但可节省网络带宽。下面给出一个用于压缩文件的例程这个程序可以用来压缩文件、文件夹等。importjavaio*importjavautilzip*publicclassZipDemo{privatestaticvoidzipFile(StringfileName,ZipOutputStreamzipOut)throwsIOException{Filefile=newFile(fileName)if(fileisDirectory()){StringstrFileName=filelist()for(inti=i<strFileNamelengthi){StringsubfileName=fileNameFileseparatorstrFileNameizipFile(subfileName,zipOut)}}if(fileisFile()){创建文件输入流对象FileInputStreamin=newFileInputStream(file)Systemoutprintln("Addingfile:"fileName)创建指向压缩原始文件的入口ZipEntryentry=newZipEntry(fileName)zipOutputNextEntry(entry)向压缩文件中输出数据intnNumberbytebuffer=newbytewhile((nNumber=inread(buffer))!=)zipOutwrite(buffer,,nNumber)zipOutcloseEntry()关闭创建的流对象inclose()}return}publicstaticvoidmain(Stringargs){if(argslength<){Systemoutprintln("zipDemozipFileNameFileNameFileName")Systemexit()}try{创建文件输出流对象FileOutputStreamout=newFileOutputStream(args)创建ZIP数据输出流对象ZipOutputStreamzipOut=newZipOutputStream(out)for(inti=i<argslengthi)zipFile(argsi,zipOut)zipOutclose()outclose()}catch(IOExceptione){Systemoutprintln(e)}}}下面这个程序则是解压缩程序。importjavaio*importjavautilzip*publicclassUnzipDemo{publicstaticvoidmain(Stringargs){if(argslength<){Systemoutprintln("Usage:javaungzip")Systemexit()}try{创建文件输入流对象实例FileInputStreamin=newFileInputStream(args)创建Zip压缩格式输入流对象实例ZipInputStreamzipin=newZipInputStream(in)获取Entry对象实例ZipEntryentrywhile((entry=zipingetNextEntry())!=){Systemoutprintln("Unzip:"entrygetName())Filefile=newFile(entrygetName())Systemoutprintln(filecreateNewFile())创建文件输出流对象实例FileOutputStreamout=newFileOutputStream(entrygetName())bytebuffer=newbyteintnNumberwhile((nNumber=zipinread(buffer,,bufferlength))!=)outwrite(buffer,,nNumber)outclose()}关闭文件流对象zipinclose()inclose()}catch(IOExceptione){Systemoutprintln(e)}}}读写Java基本数据类型DataInputStream可以让应用程序用与机器无关的方式从底层输入流读取基本的Java数据类型、如char、int。DataOutputStream让应用程序用可移植的方式把基本的Java数据类型写到输出流。DataInputStream和DataOutputStream提供例如readInt()writeInt()、readChar()writeChar()等方法可以处理Java中的基本数据类型。下面是一个应用DataInputStream和DataOutputStream的例子。importjavaio*publicclassDataIODemo{publicstaticvoidmain(Stringargs)throwsIOException{writethedataoutDataOutputStreamout=newDataOutputStream(newFileOutputStream("invoicetxt"))doubleprices={,,,,}intunits={,,,,}Stringdescs={"JavaTshirt","JavaMug","DukeJugglingDolls","JavaPin","JavaKeyChain"}for(inti=i<priceslengthi){outwriteDouble(pricesi)outwriteChar('t')outwriteInt(unitsi)outwriteChar('t')outwriteChars(descsi)outwriteChar('n')}outclose()readitinagainDataInputStreamin=newDataInputStream(newFileInputStream("invoicetxt"))doublepriceintunitStringBufferdescdoubletotal=try{while(true){price=inreadDouble()inreadChar()throwsoutthetabunit=inreadInt()inreadChar()throwsoutthetabcharchrdesc=newStringBuffer()charlineSep=SystemgetProperty("lineseparator")charAt()while((chr=inreadChar())!=lineSep)descappend(chr)Systemoutprintln("You'veordered"unit"unitsof"desc"at$"price)total=totalunit*price}}catch(EOFExceptione){}Systemoutprintln("ForaTOTALof:$"total)inclose()}}对象序列化序列化即将一个对象的状态(各个属性量)转换成字节流以后通过这些值再生成相同状态的对象。这个过程也可以通过网络实现可以先在Windows机器上创建一个对象对其序列化然后通过网络发给一台Unix机器然后在那里准确无误地重新“装配”。java对象序列化机制一般来讲有两种用途:将对象的状态保存到文件中而后能够通过读入对象状态来重新构造对象恢复程序状态或者在网络上传送对象。我们通过让类实现javaioSerializable接口可以允许类序列化。这个接口是一个特征接口。也就是说对于要实现它的类来说该接口不需要实现任何方法。它主要用来通知Java虚拟机需要将一个对象序列化。需要注意的是:并非所有类都可以序列化在cmd下我们输入serialverjavanetSocket可以得到Socket类是否可序列化的信息实际上socket是不可序列化的输出如下:ClassjavanetSocketisnotSerializableJava有很多基础类已经实现了Serializable接口比如String、Hashmap等。将对象读出或者写入流的主要类有两个:ObjectOutputStream与ObjectInputStream。这两个类分别继承自FilterOutputStream和FilterInputStream所以这两个流也属于过滤器流。ObjectOutputStream提供用来将对象写入输出流的writeObject()方法ObjectInputStream提供从输入流中读出对象的readObject()方法。使用这些方法的对象必须已经被序列化的。也就是说必须已经实现Serializable接口。下面这个程序把一个HashMap的对象hashMapOut序列化并且存放在文件mapobj中然后从mapobj中读取数据并恢复出HashMap的对象hashMapIn。importjavautil*importjavaio*publicclassSerializeMap{staticvoidputData(Mapmap){mapput("","Five")mapput("","Four")mapput("","Three")mapput("","Two")mapput("","One")}publicstaticvoidmain(Stringargs){try{MaphashMapOut=newHashMap()putData(hashMapOut)Systemoutprintln("HashMapOut:"hashMapOut)FileOutputStreamfout=newFileOutputStream("mapobj")ObjectOutputStreamobjout=newObjectOutputStream(fout)objoutwriteObject(hashMapOut)objoutclose()foutclose()FileInputStreamfin=newFileInputStream("mapobj")ObjectInputStreamobjin=newObjectInputStream(fin)MaphashMapIn=(HashMap)objinreadObject()Systemoutprintln("HashMapIn:"hashMapIn)objinclose()finclose()}catch(Exceptione){eprintStackTrace()}}}程序运行的结果是:HashMapOut:{=Three,=Five,=Two,=Four,=One}HashMapIn:{=Three,=Five,=Two,=Four,=One}文件和目录管理以上所介绍的IO流用于文件或者其他流的读写。Java还提供了一些类用于文件系统的操作例如文件和目录的创建和复制等。本小节将对这些方法进行详细的介绍。File类File类是对文件和目录的抽象表示。本节将完整地例示如何使用这个类其中包括相关的FilenameFilter接口。文件的路径有两种形式:绝对路径和相对路径。绝对路径包含它所指定的文件的完整路径信息根据绝对路径就可以唯一定位一个文件。而相对路径是针对“其他某个路径”而言的这个路径和相对路径共同定位一个文件的位置。在Java中这个“其他某个路径”总是用户当前所在的路径这个路径可以根据系统属性userdir得到。遍历目录利用File类可以遍历某一个目录下的所有文件和子目录。File类列目录的方法为list():publicStringlist()publicStringlist(FilenameFilterfilter)list()方法可以不指明任何参数这种情况下可以列出某个目录所有的文件和子目录。而如果传入FilenameFilter类对象filter作为参数则可以根据需要列出符合条件的文件和子目录。importjavaio*publicclassListDir{publicstaticvoidmain(Stringargs){try{Fileroots=FilelistRoots()Systemoutprint("Availabledrivers:")for(inti=i<rootslengthi)Systemoutprint(rootsigetAbsolutePath()"")Systemoutprintln("")Filepath=newFile("")Stringlistlist=pathlist()Systemoutprintln("Filesincurrentdirectory:")for(inti=i<listlengthi)Systemoutprintln(listi)}catch(Exceptione){eprintStackTrace()}}}运行结果如下:E:WorkJAVAJavaCodeChap>javaListDirAvailabledrivers:A:C:D:E:F:G:H:Filesincurrentdirectory:DirListjavaDirListclass下面的程序增强了列目录的操作使得只有后缀名为“java”的文件才列出来。在这个程序中我们使用了FilenameFilter接口。importjavaio*publicclassListJavaFiles{publicstaticvoidmain(Stringargs){try{Filepath=newFile("")Stringlistlist=pathlist(newDirFilter())for(inti=i<listlengthi)Systemoutprintln(listi)}catch(Exceptione){eprintStackTrace(

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

评分:

/40

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利