ImageVerifierCode 换一换
格式:DOCX , 页数:64 ,大小:312.14KB ,
资源ID:11301276      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/11301276.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(第11章 Java IO输入输出流.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

第11章 Java IO输入输出流.docx

1、第11章 Java IO输入输出流第十一章 IO/输入输出大多数应用程序都需要与外部设备进行数据交换,最常见的外部设备包含磁盘和网络,IO就是指应用程序对这些设备的数据输入与输出,在程序中,键盘被当作输入文件,显示器被当作输出文件使用。Java语言定义了许多类专门负责各种方式的输入输出,这些类都被放在java.io包中。11.1 File类 File类是IO包中唯一代表磁盘文件本身的对象,File类定义了一些与平台无关的方法来操纵文件,通过调用File类提供的各种方法,我们能够创建、删除文件,重命名文件,判断文件的读写权限及是否存在,设置和查询文件的最近修改时间。在Java中,目录也被当作Fi

2、le使用,只是多了一些目录特有的功能可以用list方法列出目录中的文件名。在Unix下的路径分隔符为(/),在Dos下的路径分隔符为(),Java可以正确处理Unix和Dos的路径分隔符,即使我们在Windows环境下使用(/)作为路径分隔符,Java仍然能够正确处理。 我们用下面的一个简单应用来演示一下File类用法,判断某个文件是否存在,存在则删除,不存在则创建,读者可以在Windows的资源管理器下观察到这个变化。程序清单:FileTest.javaimport java.io.*;public class FileTest public static void main(String

3、args) File f=new File(c:1.txt); if(f.exists() f.delete(); else try f.createNewFile(); catch(Exception e) System.out.println(e.getMessage(); System.out.println(File name:+f.getName(); System.out.println(File path:+f.getPath(); System.out.println(Abs path:+f.getAbsolutePath(); System.out.println(Paren

4、t:+f.getParent(); System.out.println(f.exists()?exists:does not exist); System.out.println(f.canWrite()?is writeable:is not writeable); System.out.println(f.canRead()?is readable:is not readable); System.out.println(f.isDirectory()?is :is not+ a directory); System.out.println(f.isFile()?is normal fi

5、le:might be a named pipe); System.out.println(f.isAbsolute()?is absolute:is not absolute); System.out.println(File last modified:+f.lastModified(); System.out.println(File size:+f.length()+ Bytes); 当运行这个程序时会因为文件1.txt的存在和不存在而出现两种结果:结果1:File name:1.txtFile path:c:1.txtAbs path:c:1.txtParent:c:existsis

6、 writeableis readableis not a directoryis normal fileis absoluteFile last modified:1051755103126File size:0 Bytes结果2:File name:1.txtFile path:c:1.txtAbs path:c:1.txtParent:c:does not existis not writeableis not readableis not a directorymight be a named pipeis absoluteFile last modified:0File size:0

7、 Bytes注:delete方法删除由File对象的路径所表示的磁盘文件。它只能删除普通文件,而不能删除目录,即使是空目录也不行。关于File类的其它方法,是没法死记硬背的,读者在需要时自己查看JDK文档,应该能够明白怎么使用。初步接触了File类,我们发现File类不能访问文件的内容,即不能够从文件中读取数据或往文件里写数据,它只能对文件本身的属性进行操作。11.2 RandomAccessFile类 RandomAccessFile类可以说是Java语言中功能最为丰富的文件访问类,它提供了众多的文件访问方法。RandomAccessFile类支持“随机访问”方式,我们可以跳转到文件的任意位

8、置处读写数据。在你访问一个文件的时候,不想把文件从头读到尾,并希望像访问一个数据库一样的访问一个文本文件,使用RandomAccessFile类就是你的最佳选择。 RandomAccessFile对象类有个位置指示器,指向当前读写处的位置,当读写n 个字节后,文件指示器将指向这n个字节后的下一个字节处。刚打开文件时,文件指示器指向文件的开头处,我们可以移动文件指示器到新的位置,随后的读写操作将从新的位置开始。RandomAccessFile在等长记录格式文件的随机(相对顺序而言)读取时有很大的优势,但该类仅限于操作文件,不能访问其他的IO设备,如网络,内存映象等。有关RandomAccessF

9、ile类中的成员方法及使用说明,请参阅JDK文档。下面是一个使用RandomAccessFile的例子,往文件中写入三名员工的信息,然后按照第二名员工,第一名员工,第三名员工的先后顺序读出。RandomAccessFile可以以只读或读写方式打开文件,具体使用哪种方式取决于我们创建RandomAccessFile类对象的构造方式:new RandomAccessFile(f,rw); /读写方式new RandomAccessFile(f,r); /只读方式注:当我们的程序需要以读写的方式打开一个文件时,如果这个文件不存在,程序会为你创建它。我们还需要设计一个类来封装员工信息。一个员工信息就是

10、文件中的一条记录,我们必须保证每条记录在文件中的大小相同,也就是每个员工的姓名字段在文件中的长度是一样的,我们才能够准确定位每条记录在文件中的具体位置。假设name中有八个字符,少于八个则补空格(这里我们用u0000),多于八个则去掉后面多余的部分。由于年龄是整型数,不管这个数有多大,只要它不超过整型数的范围,在内存中都是占4个字节大小。程序清单:RandomFileTest.javaimport java.io.*;public class RandomFileTest public static void main(String args) throws Exception Employe

11、e e1 = new Employee(zhangsan,23); Employee e2 = new Employee(Lisi,24); Employee e3 = new Employee(Wangwu,25); RandomAccessFile ra=new RandomAccessFile(c:1.txt,rw); ra.write(e1.name.getBytes(); ra.writeInt(e1.age); ra.write(e2.name.getBytes(); ra.writeInt(e2.age); ra.write(e3.name.getBytes(); ra.writ

12、eInt(e3.age); ra.close(); RandomAccessFile raf=new RandomAccessFile(c:1.txt,r); int len=8; raf.skipBytes(12); /跳过第一个员工的信息,其中姓名8字节,年龄4字节 System.out.println(第二个员工信息:); String str=; for(int i=0;ilen;i+) str=str+(char)raf.readByte(); System.out.println(name:+str); System.out.println(age:+raf.readInt();

13、System.out.println(第一个员工的信息:); raf.seek(0); /将文件指针移动到文件开始位置 str=; for(int i=0;ilen;i+) str=str+(char)raf.readByte(); System.out.println(name:+str); System.out.println(age:+raf.readInt(); System.out.println(第三个员工的信息:); raf.skipBytes(12); /跳过第二个员工信息 str=; for(int i=0;iLEN) name = name.substring(0,8);

14、else while(name.length()LEN) name=name+u0000; this.name=name; this.age=age; 运行结果:第二个员工信息:name:Lisiage:24第一个员工的信息:name:zhangsanage:23第三个员工的信息:name:Wangwuage:25c盘还多了个文件1.txt:图11.1 上面的这个程序完成了我们想要的功能,演示了RandomAccessFile类的作用。String.substring(intbeginIndex,intendIndex)方法可以用于取出一个字符串中的部分子字符串,要注意的一个细节是:子字符串中

15、的第一个字符对应的是原字符串中的脚标为beginIndex处的字符,但最后的字符对应的是原字符串中的脚标为endIndex-1处的字符,而不是endIndex处的字符。在实际生活中,我们常用的数据库和数据库管理工具实际上就是这种原理。我们的1.txt就相当于数据库的数据文件,而我们这个程序提供了往这个数据文件写入和读取数据的功能。11.3 节点流11.3.1 理解流的概念 数据流是一串连续不断的数据的集合,就象水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。对数

16、据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中的任意长度的数据,但只能先读取前面的数据后,再读取后面的数据。不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。我们将IO流类分为两个大类,节点流类和过滤流类(也叫处理流类)。程序用于直接操作目标设备所对应的类叫节点流类,程序也可以通过一个间接流类去调用节点流类,以达到更加灵活方便地读写各种类型的数据,这个间接流类就是过滤流类(也叫处理流类),我更喜欢称之为包装类。不管叫什么,都只是一个代名词而已,读者不要太在意,你可以根据自己的习惯和喜好来定。11.3.2 InputStream与OutputS

17、tream 程序可以从中连续读取字节的对象叫输入流,用InputStream类完成,程序能向其中连续写入字节的对象叫输出流,用OutputStream类完成。InputStream与OutputStream对象是两个抽象类,还不能表明具体对应哪种IO设备。它们下面有许多子类,包括网络,管道,内存,文件等具体的IO设备,如FileInputStream类对应的就是文件输入流,是一个节点流类,我们将这些节点流类所对应的IO源和目标称为流节点(Node)。很多人搞不清程序要将A文件的内容写入B文件中,程序对A文件的操作所用的是输出类还是输入类这个问题。读者也先自己想想,再记住下面的话,输入输出类是相

18、对程序而言的,而不是代表文件的,所以我们应该创建一个输入类来完成对A文件的操作,创建一个输出类来完成对B文件的操作。 InputStream定义了Java的输入流模型。该类中的所有方法在遇到错误的时候都会引发IOException异常,下面是InputStream类中方法的一个简要说明: int read()返回下一个输入字节的整型表示,,如果返回-1表示遇到流的末尾,结束。 int read(byte b)读入b.length个字节放到b中并返回实际读入的字节数。 int read(byte b,int off,int len) 这个方法表示把流中的数据读到,数组b中,第off个开始的len

19、个数组元素中. long skip(long n) 跳过输入流上的n个字节并返回实际跳过的字节数。 int availabale() 返回当前输入流中可读的字节数。 void mark(int readlimit)在输入流的当前位置处放上一个标志,允许最多再读入readlimit个字节。 void reset() 把输入指针返回到以前所做的标志处。 boolean markSupported() 如果当前流支持mark/reset操作就返回true。 void close() 在操作完一个流后要使用此方法将其关闭, 系统就会释放与这个流相关的资源。InputStream是一个抽象类,程序中实际

20、使用的是它的各种子类对象。不是所有的子类都会支持InputStream中定义的某些方法的,如skip,mark,reset等,这些方法只对某些子类有用。一个对象在没有引用变量指向它时会变成垃圾,最终会被垃圾回收器从内存中清除。对于我们创建的流对象,干嘛还要“调用close方法将它关闭,以释放与其相关的资源”呢?这相关的资源到底是些什么呢?我们在程序中创建的对象都是对应现实世界中有形或无形的事物,计算机操作系统所产生的东西当然也是现实世界中的事物,也就是说,程序中的对象也可以对应计算机操作系统所产生的一个其他东西,专业地说,这些东西叫资源,流就是操作系统产生的一种资源。当我们在程序中创建了一个I

21、O流对象,同时系统内也会创建了一个叫流的东西,在这种情况下,计算机内存中实际上产生了两个事物,一个是Java程序中的类的实例对象,一个是系统本身产生的某种资源,我们以后讲到的窗口,Socket等都是这样的情况。Java垃圾回收器只能管理程序中的类的实例对象,没法去管理系统产生的资源,所以程序需要调用close方法,去通知系统释放其自身产生的资源。OutputStream是一个定义了输出流的抽象类,这个类中的所有方法均返回void,并在遇到错误时引发IOException异常。下面是OutputStream的方法: void write(int b) 将一个字节写到输出流。注意,这里的参数是in

22、t型,它允许write使用表达式而不用强制转换成byte型。 void write(byte b) 将整个字节数组写到输出流中。 void write(byte b,int off,int len) 将字节数组b中的从off开始的len个字节写到输出流。 void flush彻底完成输出并清空缓冲区。 void close关闭输出流。计算机访问外部设备,要比直接访问内存慢得多,如果我们每一次write方法的调用都直接写到外部设备(如直接写入硬盘文件),CPU就要花费更多的时间等待外部设备;如果我们开辟一个内存缓冲区,程序的每一次write方法都是写到这个内存缓冲区中,只有这个缓冲区被装满后,系

23、统才将这个缓冲区的内容一次集中写到外部设备。使用内存缓冲区有两个方面的好处,一是有效地提高了CPU的使用率,二是write并没有马上真正写入到外设,我们还有机会回滚部分写入的数据。使用缓冲区,能提高整个计算机系统的效率,但也会降低单个程序自身的效率,由于有这么一个中间缓冲区,数据并没有马上写入到目标中去,例如在网络流中,就会造成一些滞后。对于输入流,我们也可以使用缓冲区技术。在程序与外部设备之间到底用不用缓冲区,是由编程语言本身决定的,我们通常用的C语言默认情况下就会使用缓冲区,而在Java语言中,有的类使用了缓冲区,有的类没有使用缓冲区,我们还可以在程序中使用专门的包装类来实现自己的缓冲区。

24、flush方法就是用于即使在缓冲区没有满的情况下,也将缓冲区的内容强制写入到外设,习惯上称这个过程为刷新。可见,flush方法不是对所有的OutputStream子类都起作用的,它只对那些使用缓冲区的OutputStream子类有效。如果我们调用了close方法,系统在关闭这个流之前,也会将缓冲区的内容刷新到硬盘文件的。 作者开发过一个邮件服务器程序,需要7*24小时不间断工作,这个服务器程序要面对internet上各种可能的非法格式的数据输入和攻击,而我的程序正好又没考虑到某种非法格式的数据,一旦碰到这样的情况,程序就会崩溃。有经验的人都知道,为了找出服务器程序崩溃的原因,我们可以将程序每次

25、接收到的数据都记录到一个文件中,当服务器程序崩溃后,我们便打开这个记录文件,查看最后记录的那条数据,这个数据就是让我的程序毙命的罪魁祸首,然后拿着这条数据一步步测试我们的程序,就很容易找出程序中的问题了。遗憾的是,我每次用最后记录的这条数据测试我的程序,程序均安然无恙。最后,我发现就是因为有缓冲区的原因,缓冲区的内容还没来得及刷新到硬盘文件,程序就崩溃了,所以,文件中并没有记录最后接收到的那些数据,我在文件中看到的最后以条记录并不是真正最后接收到的那条数据。发现了这个原因,我修改程序,在每一次调用write语句后,都立即调用flush语句,这样,我就终于找到了肇事元凶,并修复了程序的这个漏洞。

26、尽管我以前从来没有真正认真思考和编程试验过缓冲区问题,但是正因为还有那么一点点概念和印象,所以,在出现问题时,我才能从多方面去思考并最终解决问题。我建议读者花更多的时间去开阔自己的知识面和思维,了解更多的原理,而不是去花大量时间去死记硬背某些细节和术语,特别是一个类中的每个函数名的具体拼写、具体的参数形式,Java中有哪些关键字等这些死板的东西,只要有个印象就足够了。11.3.3 FileInputStream与FileOutputStream这两个流节点用来操作磁盘文件,在创建一个FileInputStream对象时通过构造函数指定文件的路径和名字,当然这个文件应当是存在的和可读的。在创建一

27、个 FileOutputStream对象时指定文件如果存在将要被覆盖。下面是对同一个磁盘文件创建FileInputStream对象的两种方式。其中用到的两个构造函数都可以引发FileNotFoundException异常:FileInputStream inOne=new FileInputStream(hello.test);File f = new File(hello.test); FileInputStream inTwo = new FileInputStream(f);尽管第一个构造函数更简单,但第二个构造函数允许在把文件连接到输入流之前对文件做进一步分析。FileOutputSt

28、ream对象也有两个和FileInputStream对象具有相同参数的构造函数,创建一个FileOutputStream对象时,可以为其指定还不存在的文件名,但不能是存在的目录名,也不能是一个已被其他程序打开了的文件。FileOutputStream先创建输出对象,然后再准备输出。其实在上一章中讲Properties类的时候,我们已经使用过这两个类。在下面的例子中,我们用FileOutputStream类向文件中写入一串字符,并用FileInputStream读出。程序清单:FileStream.javaimport java.io.*;public class FileStream publ

29、ic static void main(String args) File f = new File(hello.txt); try FileOutputStream out = new FileOutputStream(f); byte buf=www.it315.org.getBytes(); out.write(buf); out.close(); catch(Exception e) System.out.println(e.getMessage(); try FileInputStream in = new FileInputStream(f); byte buf = new byte1024; int len = in.read(buf); System.out.println(new String(buf,0,len); catch(Exception e) System.out.println(e.getMessage(); 编译运行上面的程序,我们能够看到当前目录下产生了一个hello.txt的文件,用记事本程序打开这个文件,能看到我们写入的内容。随后,程序开始读取文件中的内容,并将读取到

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1