Java程序设计-12-基本输入输出处理.ppt_第1页
Java程序设计-12-基本输入输出处理.ppt_第2页
Java程序设计-12-基本输入输出处理.ppt_第3页
Java程序设计-12-基本输入输出处理.ppt_第4页
Java程序设计-12-基本输入输出处理.ppt_第5页
已阅读5页,还剩49页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Java程序设计,第12章 基本I/O处理,学习目标,理解流的概念,掌握I/O类体系 理解文本流和字节流、节点流和加工流 理解流的处理链构造,熟悉常用加工流并能灵活应用 理解File,能够利用File实例分析文件属性和基本的文件操作 掌握顺序文件的读/写过程 能够应用RandomAccessFile完成随机文件访问 理解串行化,能够定义可串行化的类,并实现对象的串行化存取,12.1 流,I/O的形式分为四种: 控制台(console, 如DOS窗口)。例如打印到显示器/键盘读入 文件(file)读/写,以文件为读/写对象。 网络接口(TCP/UDP端口)读/写,例如,网上冲浪、网络聊天、邮件发

2、送。 程序(线程)间通信,例如,数据传输。,12.1.1 什么是流,简单的说流就是一个传送有序的字节序列。读者更可以把它想象成为一个数据节点和程序之间建立起来的连接通道上的字节序列。换句话说,流就是对输入数据源和输出目的地的抽象表示。,下图 流是输入和输出设备的抽象,当把数据写入流时,该流被称为输出流。输出流可以连接硬盘上的文件、网络上的另一端等任何可以接收字节序列的设备。 同样可以把从中读取数据的流称为输入流,输入流连接的数据源可以是任何串行数据源,如磁盘文件、网络另一端的信息发送程序、键盘等。,12.1.2流的分类,节点流 可以直接和能够提供输入数据的数据源和接受数据的目的地建立直接的联系

3、 加工流 能够改善应用开发性能和效率的具有特殊功能的I/O流,这些流可以对流进行再处理,12.1.3输入流的基本方法,12.1.4输出流的基本方法,12.2字符流和字节流,字符流 Reader和Writer是用于读取字符流的两个字符流类的抽象父类,Reader和Writer是用于读取字符流的两个字符流类的抽象父类,准确地说,它们可以象读写字符流一样读写字节流 。 字符流是基于Unicode编码的。,字节流 输入流InputStream和输出流OutputStream也是抽象类,它们是一切字节输入/输出类的超类,也是抽象类。,12.3节点流,节点流 就是能够直接和内存、文件、管道这些数据的实际来

4、源和目的地设备连接。,import java.lang.Exception; class TestInput public static void main(String args) throws Exception /*准备一个字节数组,用作接收从键盘上输入内容的缓冲区*/ byte b = new byte10; /number保存每次从输入流中读入到缓冲区b的字节数 int number = 0; number = System.in.read(b); for(int i=0;ib.length;i+) System.out.println(bi); System.out.println

5、(Received number= + number ); ,12.4流的处理链,12.4.1过滤器流,过滤器(Filter)流 是为了某种目的过滤字节或字符的数据流。它也是一个加工流,建立在基本的字符/字节流。Java的I/O类中包含四个过滤器流,分别是支持字符和字节的输入/输出流。,protected FilterInputStream(InputStream in) protected FilterOutputStream(OutputStream out) protected FilterReader(Reader in) protected FilterWriter(Writer o

6、ut),12.4.2转换流,将字节流转换为字符流 上面的语句中,InputStreamReader类的作用是建立起从字节流到字符流之间的桥梁,它从字节流中读入若干字节的数据,然后根据设定的字符集将其转换为字符。,InputStreamReader isr = new InputStreamReader(System.in);,OutputStreamWriter osr = new OutputStreamWriter(System.out);,类似的,将字符流转换为字节流,/程序12-2 转换字节流到字符流 import java.io.IOException; import java.io

7、.InputStreamReader; public class InputStreamReaderDemo public static void main(String args) throws IOException InputStreamReader isr=new InputStreamReader(System.in,GBK); int c=0; while(c=isr.read()!=-1) System.out.println(char)c); ,12.4.3数据输入和输出流,DataInputStream和DataOutputStream是两个可以按照Java数据类型(无关底层

8、的数据类型)进行存取的数据流。,DataInput和DataOutput的实例,public class DataInOutDemo public static void dataIn(String fileName) throws IOException FileInputStream fis=new FileInputStream(fileName); DataInputStream dis=new DataInputStream(fis); System.out.print(从文件中读取了:); while(true) try int x=dis.readInt();/从文件读一个整数

9、System.out.printf(%dt,x); catch(EOFException e)/到达文件尾 break;/退出循环 dis.close(); ,public class DataInOutDemo /输出10个整数到指定的文件 public static void dataOut(String fileName) throws IOException FileOutputStream fos=new FileOutputStream(fileName); DataOutputStream dos=new DataOutputStream(fos); Random rand=ne

10、w Random(); for(int i=0;i10;i+) int x=rand.nextInt(10000); dos.writeInt(x); dos.close(); ,12.4.4缓冲流,应用程序使用缓冲流,可以减少读写的次数,加快输入和输出的速度,提高应用的性能。缓冲数据流中均包含一个字节/字符缓冲区数组,从而实现成块的读写。当然这个成块的读写过程对于应用程序来讲是透明的,无须关心。,例如:还是向文件进行输出,上一小节中提到了下面的方法: 如果加上了缓冲之后,则变成了下面的代码:,PrintStream ps = new PrintStream(out.dat);,PrintSt

11、ream ps = new PrintStream( new BufferedOutputStream( new FileOutputStream(out.dat);,两个不同输出程序的效率比较 一个不用缓冲区输出数据到文件的程序 用缓冲实现向磁盘上文件输出数据的程序,12.4.5打印输出流,基于数据输出流的文件输出,保存到文件中的是二进制的内容,无法使用文本工具浏览文件内容。Java提供了PrintStream和PrintWriter把数据输出到文件中,可以方便的使用文本工具进行浏览,public class PrintStreamDemo public static void main(S

12、tring args) throws FileNotFoundException /PrintStream out = new PrintStream(test.dat); PrintWriter out = new PrintWriter(test.dat); Random rand = new Random(); for (int i = 0; i 10; i+) int x = rand.nextInt(100000); out.println(x); out.close(); ,12.4.6如何利用流编写程序,基本的I/O过程可以遵从以下原则: 确定要访问设备的数据类型是字节设备还是文

13、本设备,来决定采用何种类型的节点流进行连接。 根据是准备从数据源输入内容,还是准备向目的地输出内容,确定合适的I/O类创建节点流。 根据应用程序的特性确定选择合适的输出流或输入流,并对下层输入输出流进行封装,如有必要,需要借助InputStreamStreamReader或OutputStreamWriter进行转换。常见的如基于文本行的文本输入输出、基于Java数据类型的数据流输入输出,格式化输出流PrintWriter等。 考虑是否添加缓冲流来改善输入和输出性能,如需要,修改第3步的实例化过程、一般将缓冲流置于中间层,参见缓冲流中的例子。 输入输出结束后,可以直接关闭最外层的流即可。,12

14、.5文件处理,应用程序中经常需要从外部的文件中读取信息和向外部文件写出数据进行保存,在这个过程中,简单的程序如同例9-4和例9-5都已经作了简单的介绍,但在实际中,经常会发生各种意外的情况,例如,如果需要打开的文件不存在,或者要创建的文件没有创建成功,甚至创建时覆盖了一个已经存在的同名文件,等等诸如此类的情况,因此,在文件处理中,除了能够完成高效的I/O处理外,还要在关键的打开、读写和关闭等关键处理上注意异常的发生,提高程序的质量。,12.5.1 File,实际应用中直接利用文件名指向一个将要创建的文件存在一定的风险,例如是否有同名的文件存在,抑或在不同的环境中文件的属性会有一定的变化。 1

15、File对象 File是对文件和路径名的一种抽象表示,应用程序中经常使用File对象来指向自己希望创建或引用的文件或目录的路径。具体来说,它有两个作用: 应用程序利用它检查它所引用的物理文件或目录,看是否与真实的文件或目录相对应。 应用程序可以利用它创建文件输出/输出流,进行文件的处理。 读者需要注意的是File对象并不包含文件内容,应用程序只是利用它处理文件的各种属性。,2 创建File对象 下面列出了File对象的四种构造函数,应用中可以根据情况进行选择: File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新

16、File 实例。 File(String pathname) 通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。 File(String parent, String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。 File(.URI uri) 通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例,用于网络访问。,例如,下面的代码创建了一个封装了指定路径D:/mydata/和一个文件名为score.txt的文件对象,它应用了第三个构造函数: 或者,可以使用第二个构造函数的形式: 注意:上述

17、代码中应该保证在D分区中有一个mydata的目录,该构造函数并不会直接创建一个不存在的目录。,File myFile = new File(D:/mydata,score.txt);,File myFile = new File(D:/mydata/score.txt);,3 路径分界符及路径移植性问题 在不同的系统中路径分隔符是不一样的,例如在unix系列的操作系统中,分割符定义为/,而在Windows系统下则被定义为,只是由于转义的规定被写为。 路径的表示在不同的系统中也是不一样的,例如Windows系统下的路径在绝对表示时,通常包含分区,如C:mydata2006score.txt在Ja

18、va代码中即被表示为C:mydata2006score.txt,而在Unix系统下绝对路径却是以/开始,例如/mydata/2006/score.txt。,如何避免?,因此在Java应用中就需要尽量考虑不要在代码中直接嵌入具体的路径表示,而要用相对路径来表示,相对路径不包括具体的绝对路径前缀,避免了不同操作系统的影响。,String homeDir = System.getenv(MyAppHome); File myFile = new File(homeDir + File.separator + score.txt);,一个模拟的应用,String homeDir = System.ge

19、tenv(MyAppHome); File myFile = new File(homeDir+File.separator+score.txt); if(!myFile.exists() System.out.println(The file has not been found! ); System.exit(-1); /退出程序执行 ,5 文件的属性测试,String homeDir = System.getenv(MyAppHome); File myFile = new File(homeDir+File.separator+score.txt); if(!myFile.exists

20、() System.out.println(The file has not been found! ); System.exit(0); /退出程序执行 ,6 目录及目录操作,7 其它文件操作,一个转移目录下文件的实例,12.5.2顺序读写文件,顺序读写文件 顾名思义,顺序读写文件就是按照顺序一个字节或一个字符的对文件的内容进行输入输出,不能回读或回写,也不能随意指定读写位置,而只能从前到后。,public class AccountTools public static Map getAccountFromFile(String fn) throws IOException, Number

21、FormatException, ParseException Map accounts=new HashMap(); BufferedReader in=new BufferedReader(new FileReader(fn); String info=null;/用来保存每次读入的文件内容 while(true) info=in.readLine();/每次读取文件一行 if(info=null)/若返回值为null,则表示已到文件尾 break; String s=info.split(“,”);/利用文件的内容分隔符分解此行 Account a=new Account(s0,s1,I

22、nteger.parseInt(s2); accounts.put(a.getId(), a); return accounts; ,12.5.3随机读写文件,RandomAccessFile Java提供了RandomAccessFile类,用于随机存取文件的读取和写入。它属于字节流,也属于节点流的一种,而且本身即是输入流又是输出流,1. 如何构造RandomAccessFile对象 构造函数1: RandomAccessFile(File file, String mode) /创建从中读取和向其中写入(可选)的随机存取文件流,该文件由 File 参数指定。 构造函数2: RandomAc

23、cessFile(String name, String mode) /创建从中读取和向其中写入(可选)的随机存取文件流,该文件具有指定名称。,其中,mode 参数指定用以打开文件的访问模式。允许的值及其含意为: 例如,如果希望对已经存在的文件进行更新操作,可以采用如下代码:,RandomAccessFile raf = new RandomAccessFile(D:/mydata/student.txt,rw);,2 随机存取的实现机理 随机存取文件的行为类似存储在文件系统中的一个大型字节数组。存在指向该隐含数组的光标或索引,称为文件指针。 输入操作从文件指针指向处开始读取字节,并随着对字节

24、的读取而前移此文件指针。 如果随机存取文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。 该文件指针可以通过 getFilePointer 方法读取,并通过 seek或skipBytes方法设置随机位置.,RandomAccessFile类的主要方法,随机文件访问程序,第一部分,打开文件,public class TestRandomAccessFile public static void main(String args) RandomAccessFile raf = null

25、; String info = null; String rec= null; try raf= new RandomAccessFile(d:/log/student.txt,rw); catch (FileNotFoundException e) System.exit(0); ,第二部分,文件更新,try while(info=raf.readLine()!=null) rec = info.split(,); if(pareTo(MATH)=0) raf.seek(raf.getFilePointer()-6); raf.writeBytes(MaTH); raf.skipBytes(

26、2); raf.close(); catch (IOException e) System.exit(0); ,程序运行需要注意: 执行和分析上面的程序,需要注意的是以下几个方面的问题: 建立随机读写文件的模式 如何灵活的利用seek和skip实现灵活的定位 随机读写尚不能支持对文件的直接插入操作,仅仅实现了修改操作,因此需要避免因为写入了比需要修改的信息多的字节,而导致后续的内容受到破坏。 注意读写中的异常处理 程序没有考虑字符集的问题,对于实验用的文本文件,其原始格式都是按照一个字符占一个字节,一个汉字占2个字节进行分析的,在运行时读者需要注意,如果有汉字的话,可能是乱码,此问题请参考有关

27、国际化编程中的有关解释。,12.6对象串行化,串行化 对象串行化使得应用能够以字节序列形式保存一个对象的状态(对象的属性值),以便随后被重新构造为原来的对象。 在Java的I/O类中,有两个特别的类ObjectOutputStream和ObjectInputStream可以实现对象的串行化存取。 Java中的串行化首先应用在RMI(Remote Method Invocation)环境,RMI允许在一个虚拟机中的对象通过Internet传递参数去引用存在于另外一个虚拟机中的对象的方法,并获得返回值。,串行化的对象,如果要使对象能够在网络内传输或者持久化保存,就必须使对象成为可串行化。在Java

28、中,一个类的对象要可串行化的必要条件是:定义类的时候,该类要实现Serializable接口。,import java.io.Serializable; public class Student implements Serializable String sid; /学号 String name; /姓名 Student(String sid, String name) super(); this.sid = sid; = name; public String toString() return id=+sid+ name=+name; /读者可自己继续添加类的其它部分

29、定义 ,关于串行化化类 在进行类的串行化实现声明时,要注意类的继承性。如果一个类的父类已经声明为可串行化的,那么子类就无需重复声明了。 在进行属性声明时,一定要注意属性类型是否已实现串行化。 同时需要注意的是,Java中的基本数据类型、Date类等已经实现了可串行化,在应用中可直接使用。,ObjectOutputStream的主要输出方法,对象的串行化存取,public class StudentManager /限制了该列表只处理Student类型的对象 private List students = new ArrayList(10); StudentManager() /将对象追加到列表

30、对象中 void addStudent(Student student) this.students.add(student); void save(String filename) throws FileNotFoundException, IOException / void restore(String filename) throws FileNotFoundException, IOException ,/将列表中的对象都保存在文件中 void save(String filename) throws FileNotFoundException, IOException Object

31、OutputStream out = null; /判断集合中是否有对象存在,如果没有,就不再执行保存操作 if(this.students.size()=0) return; /* 开始保存对象列表,首先创建一个对象输出流,运行中可能抛出异常*/ out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream(filename); /首先将需要保存的对象总数保存到文件开始处,以便读取时容易处理 out.writeInt(students.size(); for(Student student:stude

32、nts)/开始循环保存每个对象 out.writeObject(student); out.close();/关闭输出流 ,void restore(String filename) throws FileNotFoundException, IOException ObjectInputStream in =null; Object student=null; this.students.clear(); /首先将列表对象清空 in = new ObjectInputStream( new BufferedInputStream(new FileInputStream(filename);

33、try int count = in.readInt(); /首先读取该文件中对象的数量 int i=0; while(icount) student=in.readObject(); /返回的类型是Object this.addStudent(Student)student); System.out.println(student); i+; catch (ClassNotFoundException e) /e.printStackTrace(); finally in.close(); /关闭输入流 ,串行化的问题,串行化看起来比较简单,只须实现一个没有任何方法的接口即可,但实际上还是会

34、出现一些特别的情况需要考虑。例如,下面的几个问题: 一个对象是否一定能够被串行化? 如果不希望保存对象的某些属性怎么办? 一个对象的状态发生了改变,再次保存时是重新保存还是覆盖原有的内容?,串行化的问题(cont.),1 串行化的条件 在实现Serializable接口时,为了类对象能够充分串行化,则要求该类中的所有字段必须均为可串行化的,但是实际中可能还有一种情况,某个类的父类不是可串行化的,那么子类是否就无法串行化了?并非如此,只要满足以下条件,子类同样可以被串行化: 每个不可被串行化的父类必须有一个没有任何参数的构造函数。 子类必须实现Serializable接口。 子类必须对没有串行化

35、的父类中的字段进行串行化。简单的,就是在子类中自定义实现readObject和writeObject方法.,自定义串行化类,public class Student implements Serializable String sid; /学号 String name; /姓名 Image pic; /保存照片,但需要自己定义如何保存 Student(String sid, String name) super(); this.sid = sid; = name; /自定义串行化输入方法 private void readObject(ObjectInputStream in) throws IOException /自定义串行化输入方法,因为此例中的I

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论