Download presentation
Presentation is loading. Please wait.
1
第10章 输入与输出 本章要点 10.1 输入与输出基础 10.2 文件输入/输出 思考与练习10
第10章 输入与输出 输入/输出处理是程序设计中重要的一个部分,比如从键盘读取数据、从文件中读取数据或向文件中写数据等等。Java把这些不同类型的输入、输出源抽象为流(stream),用统一接口来表示,从而使程序简单明了。本章主要介绍Java程序输入输出的实现和文件与目录的管理。 本章要点 10.1 输入与输出基础 10.2 文件输入/输出 思考与练习10
2
10.1 输入与输出基础 Java的输入输出功能必须使用类库java.io来实现,这个类库中的类大部分是用来完成流式输入输出的类。Java Applet程序的特点如下。 流的概念 流式输入输出是一种很常见的输入输出方式。流是指在计算机的输入与输出之间运动的数据序列。流序列中的数据既可以是未经加工的原始的二进制数据,也可以是经一定编码处理后符合某种格式规定的特定数据。 Java程序通过流来完成输入/输出。流通过Java的输入/输出系统与物理设备链接。尽管与它们链接的物理设备不尽相同,所有流的行为具有同样的方式。这样,相同的输入/输出类和方法适用于所有类型的外部设备。这意味着一个输入流能够抽象多种不同类型的输入:磁盘文件,键盘或网络套接字。同样,一个输出流可以输出到控制台,磁盘文件或相连的网络。Java中流的实现是在java.io包定义的类层次结构内部的。 在Java中,把不同类型的输入、输出源(键盘、文件、网络等)抽象为流(Stream),而其中输入或输出的数据则称为数据流(Data Stream),用统一的方式来表示,从而使程序设计简单明了。 输入流只能从中读取数据,而不能向其写出数据;输出流只能向其写出数据,而不能从中读取数据。
3
10.1 输入与输出基础 字节流与字符流 Java定义了两种类型的流:字节类和字符类。它们属于基本输入/输出流类,是其他输入/输出流类的父类。字节流(byte stream)为处理字节的输入和输出提供了方便的方法,例如,使用字节流读取或书写二进制数据。字符流(character stream)为字符的输入和输出处理提供了方便。它们采用了统一的编码标准,因而可以国际化。当然,在某些场合,字符流比字节流更有效。 需要声明:在最底层,所有的输入/输出都是字节形式的。基于字符的流只为处理字符提供方便有效的方法。 下面是对字节流和字符流的介绍。 字节流类 字节流由两个类层次结构定义。在顶层有两个抽象类:InputStream 和 OutputStream。每个抽象类都有多个具体的子类,这些子类对不同的外设进行处理,例如磁盘文件,网络连接,甚至是内存缓冲区。 需要说明的是,要使用流类,必须导入java.io包。 书中表10-1显示了字节流类。
4
10.1 输入与输出基础 字节流与字符流 抽象类InputStream 和 OutputStream定义了实现其他流类的关键方法。最重要的两种方法是read()和write(),它们分别对数据的字节进行读写。两种方法都在InputStream 和OutputStream中被定义为抽象方法,它们被派生的流类重载。 InputStream类中的常用方法有: int read():从输入流中读一个字节,形成一个0~255之间的整数返回(是一个抽象方法)。 int read(byte b[]):读多个字节到数组中。 int read(byte b[], int off, int len):从输入流中读取长度为len的数据,写入数组b中从索引off开始的位置,并返回读取的字节数。 对于这三个方法,若返回-1,表明流结束。
5
10.1 输入与输出基础 10.1.2 字节流与字符流 skip():跳过流中若干字节数 available():返回流中可用字节数
10.1 输入与输出基础 字节流与字符流 skip():跳过流中若干字节数 available():返回流中可用字节数 mark():在流中标记一个位置 reset():返回标记过得位置 markSupport():是否支持标记和复位操作 close():关闭流 OutputStream类的常用方法有: write(int b):将一个整数输出到流中(只输出低位字节,抽象方法) nwrite(byte b[]):将字节数组中的数据输出到流中 nwrite(byte b[], int off, int len):将数组b中从off指定的位置开始,长度为len的数据输出到流中 flush():刷空输出流,并将缓冲区中的数据强制送出
6
10.1 输入与输出基础 字节流与字符流 字符流类 字符流类由两个类层次结构定义。顶层有两个抽象类:Reader和Writer。这些抽象类处理统一编码的字符流。Java中这些类含有多个具体的子类。 字符流类如书中表10-2所示。 抽象类Reader和Writer定义了几个实现其他流类的关键方法。其中两个最重要的是read()和write(),它们分别进行字符数据的读和写。这些方法被派生流类重载。 Java的输入/输出类库中包含的流类很多,这里只作了一个简要的介绍。更详细的内容可以参看类库手册。
7
10.1 输入与输出基础 标准输入/输出 Java程序使用字符界面与系统标准输入输出间进行数据通信,即从键盘读入数据,或向屏幕输出数据,是十分常见的操作。为此而频频创建输入输出流类对象将很不方便。因此,Java系统事先定义好三个流对象,分别与系统的标准输入、标准输出和标准错误输出相联系。 所有的Java程序自动导入java.lang包。该包定义了一个名为System的类,该类封装了运行时环境的多个方面。例如,使用它的某些方法,你能获得当前时间和与系统有关的不同属性。System 同时包含三个预定义的流变量:in,out和err。这些成员在System中是被定义成public和static型的,这意味着它们可以不引用特定的System对象而被用于程序的其他部分。
8
10.1 输入与输出基础 标准输入/输出 System.out是标准的输出流,默认情况下,它指的是显示设备。System.in是标准输入,默认情况下,它指的是键盘。System.err指的是标准错误流,它默认是显示设备。这些流也可以重定向到任何兼容的输入/输出设备。 System.in 是InputStream的对象;System.out和System.err是PrintStream的对象。尽管它们用来读写外设的字符,但它们都是字节流。 (1)标准输入 Java的标准输入System.in是InputStream类的对象,当程序中需要从键盘读入数据的时候,只需调用System.in的read()方法即可。如下面的语句将从键盘读入一个字节的数据: char ch = System.in.read();
9
10.1 输入与输出基础 10.1.3 标准输入/输出 在使用System.in.read()方法读入数据时,需要注意如下几点:
10.1 输入与输出基础 标准输入/输出 在使用System.in.read()方法读入数据时,需要注意如下几点: System.in.read()语句必须包含在try块中,且try块后面应该有一个可接收IOException异常的catch块。如下例所示: try { ch = System.in.read(); } catch(IOException e){ … } 执行System.in.read()方法将从键盘缓冲区读入一个字节的数据,然而返回的却是16比特的整型量的低位字节是真正输入的数据,其高位字节是全零。
10
10.1 输入与输出基础 标准输入/输出 另外,作为InputStream类的对象,System.in只能从键盘读取二进制的数据,而不能把这些比特信息转换为整数、字符、浮点数或字符串等复杂数据类型的量。 当键盘缓冲区中没有未被读取的数据时,执行System.in.read()将导致系统转入阻塞(block)状态。在阻塞状态下,当前流程将停留在上述语句位置且整个程序被挂起,等待用户输入一个键盘数据后,才能继续运行下去;所以程序中有时利用System.in.read()语句来达到暂时保留屏幕的目的。 例如,下面的语句段: System.out.println("Press any key to finish the program"); try { char test=(char)System.in.read( ); } catch(IOException e) {…}
11
10.1 输入与输出基础 10.1.3 标准输入/输出 (2) 标准输出
10.1 输入与输出基础 标准输入/输出 (2) 标准输出 Java的标准输出System.out是打印输出流PrintStream类的对象。PrintStream是过滤输出类流FilterOutputStream的一个子类,其中定义了向屏幕输送不同类型数据的方法print()和println()。 println()方法有多种形式,概括起来可表述为: public void println ( 类型 变量或对象 ); println()的作用是向屏幕输出其参数指定的变量或对象,然后再换行,使光标停留在屏幕下一行第一个字符的位置。如果println()方法的参数为空,则将输出一个空行。 println()方法可输出多种不同类型的变量或对象,包括boolean,double,float,int,long类型的变量以及Object类的对象。 print()方法的使用情况与println()方法完全相同,也可以实现在屏幕上输出不同类型的变量和对象的操作。不同的是,print()方法输出对象后并不附带一个回车,下一次输出时,将输出在同一行中。
12
10.2 文件输入/输出 Java提供了一系列的读写文件的类和方法。在Java中,所有文件都是字节形式的。Java提供从文件读写字节的方法,而且允许在字符形式的对象中使用字节文件流。 Java文件和目录管理 文件是用来保存数据的,目录是管理文件的特殊机制,同类文件保存在同一个目录下可以简化文件管理。因此,掌握文件和目录的操作对于编程人员是十分必须的。 Java支持文件管理和目录管理,它们都是由专门的java.io.File类来实现。File类也属于java.io包中,但它不是InputStream或者OutputStream的子类。 每个File类的对象表示一个磁盘文件或目录,其对象属性中包含了文件或目录的相关信息,如名称、长度、所含文件个数等,调用它的方法则可以完成对文件或目录的常用管理操作,如创建、删除等。
13
10.2 文件输入/输出 10.2.1 Java文件和目录管理 1.创建File类的对象
10.2 文件输入/输出 Java文件和目录管理 1.创建File类的对象 每个File类的对象都对应了系统的一个磁盘文件或目录,所以创建File类对象时需指明它所对应的文件或目录名。 File类共提供了三个不同的构造方法,以不同的参数形式灵活地接收文件和目录名信息。 (1)File(String path):字符串参数path指明了新创建的File对象对应的磁盘文件或目录名及其路径名。 path参数也可以对应磁盘上的某个目录,如“c:\java\temp”或“java\temp”。 (2)File(String path,String name):第一个参数path表示所对应的文件或目录的绝对或相对路径,第二个参数name表示文件或目录名。 这里将路径与名称分开的好处是相同路径的文件或目录可共享同一个路径字符串,管理、修改都较方便。 (3)File(File dir,String name):这个构造方法使用另一个已经存在的代表某磁盘目录的File对象作为第一个参数,表示文件或目录的路径,第二个字符串参数表述文件或目录名。
14
10.2 文件输入/输出 10.2.1 Java文件和目录管理 2.获取文件或目录属性
10.2 文件输入/输出 Java文件和目录管理 2.获取文件或目录属性 一个对应于某磁盘文件或目录的File对象一经创建,就可以通过调用它的方法来获得该文件或目录的属性。 其中,较常用的方法如下: (1)判断文件或目录是否存在: pub1ic boo1ean exists(); 若文件或目录存在,则返回true;否则返回false (2)判断是文件还是目录: public boolean isFile(); 若对象代表有效文件,则返回true pub1ic boolean isDirectory(); 若对象代表有效目录,则返回true
15
10.2 文件输入/输出 10.2.1 Java文件和目录管理 2.获取文件或目录属性 (3)获取文件或目录名称与路径:
10.2 文件输入/输出 Java文件和目录管理 2.获取文件或目录属性 (3)获取文件或目录名称与路径: public String getName(); 返回文件名或目录名 public String getPath(); 返回文件或目录的路径 (4)获取文件的长度: public long length(); 返回文件的字节数 (5)获取文件读写属性 public boolean canRead(); 若文件为可读文件,则返回true,否则返回false public boolean canWrite(); 若文件为可写文件,返回true,否则返回false
16
10.2 文件输入/输出 10.2.1 Java文件和目录管理 2.获取文件或目录属性 (6)列出目录中的文件:
10.2 文件输入/输出 Java文件和目录管理 2.获取文件或目录属性 (6)列出目录中的文件: public Strins[] list(); 将目录中所有文件名保存在字符串数组中返回 (7)比较两个文件或目录 public boolean equals(File f); 若两个File对象相同,则返回true
17
10.2 文件输入/输出 10.2.1 Java文件和目录管理 3.文件或目录操作
10.2 文件输入/输出 Java文件和目录管理 3.文件或目录操作 File类中还定义了一些对文件或目录进行管理、操作的方法,常用的有如下几种: (1)重命名文件: pub1ic boolean renameTo(FilenewFile); 将文件重命名成newFile对应的文件名 (2)删除文件: public void delete(); 将当前文件删除 (3)创建目录: public boolean mkdir(); 创建当前目录的子目录
18
10.2 文件输入/输出 文件输入/输出流 使用File类,可以方便地建立与某磁盘文件的连接,但是,如果希望从磁盘文件读取数据,或者将数据写入文件,还需要使用文件输入/输出流类FileInputStream和FileOutputStream。 下面是它们的形式: FileInputStream(String fileName) throws FileNotFoundException FileOutputStream(String fileName) throws FileNotFoundException 这里,fileName指定需要打开的文件名。当你创建了一个输入流而文件不存在时,引发FileNotFoundException异常。对于输出流,如果文件不能生成,则引发FileNotFound Exception异常。如果一个输出文件被打开,所有原先存在的同名的文件被破坏。
19
10.2 文件输入/输出 文件输入/输出流 当你对文件的操作结束后,需要调用close( )来关闭文件。该方法在FileInputStream和FileOutputStream中都有定义。例如: void close( ) throws IOException 为读文件,可以使用在FileInputStream中定义的read( )方法。例如: int read( ) throws IOException 该方法每次被调用,它仅从文件中读取一个字节并将该字节以整数形式返回。当读到文件尾时,read( )返回-1。该方法可以引发IOException异常。 向文件中写数据,需用FileOutputStream定义的write()方法。它的最简单形式如下: void write(int byteval) throws IOException 该方法按照byteval指定的数向文件写入字节。尽管byteval作为整数声明,但仅低8位字节可以写入文件。如果在写的过程中出现问题,一个IOException异常被引发。
20
10.2 文件输入/输出 10.2.2 文件输入/输出流 利用文件输入、输出流完成磁盘文件的读写一般应遵循如下的步骤:
10.2 文件输入/输出 文件输入/输出流 利用文件输入、输出流完成磁盘文件的读写一般应遵循如下的步骤: 1.利用文件名字符串或File对象创建输入输出流对象 FileInputStream有两个常用的构造方法: (1)FileInputStream(String FileName); 利用文件名(包括路径名)字符串创建从该文件读入数据的输入流。 (2)FileInputStream(File f); 利用已存在的File对象创建从该对象对应的磁盘文件中读入数据的文件输入流。 需要注意的是:无论哪个构造方法,在创建文件输入或输出流时都可能因给出的文件名不对或路径不对,或文件的属性不对等,不能读出文件而造成错误,此时系统会抛出异常FileNotFoundException。所以创建文件输入、输出流并调用构造方法的语句应该被包括在try块中,并有相应的catch块来处理它们可能产生的异常。
21
10.2 文件输入/输出 10.2.2 文件输入/输出流 2.从文件输入/输出流中读写数据
10.2 文件输入/输出 文件输入/输出流 2.从文件输入/输出流中读写数据 从文件输入、输出流中读写数据有两种方式,一是直接利用FileInputStream和FileOutputStream自身的读写功能;一是以FileInputStream和FileOutputStream为原始数据源,再套接上其他功能较强大的输入、输出流完成文件的读写操作。 为了能更方便地从文件中读写不同类型的数据,一般都采用第二种方式,即以FileInputStream和FileOutputStream为数据源完成与磁盘文件的映射连接后,再创建其他流类的对象从FileInputStream和FileOutputStream对象中读写数据。 一般较常用的是过滤流的两个子类DataInputStream和DataOutputStream,甚至还可以进一步简化为如下写法: Fi1e MyFi1e= new File ("MyTextFile" ); DataInputStream din =new DataInputStream(new FileInputStream (MyEile)); DataOutputStream dour=new DataOutputStream(new FileOutputStream(MyFi1e));
22
10.2 文件输入/输出 随机存取文件 FileInputStream和FileOutputStream实现的是对磁盘文件的顺序读写,而且读和写要分别创建不同的对象。相比之下,Java中还定义了另一个功能更强大,使用更方便的类—RandomAccessFile,它可以实现对文件的随机读写操作。 1.创建RandomAccessFile对象 RandomAccessFile类有两个构造方法: RandomAccessFile(String name, String mode); RandomAccessFile(File f, String mode); 无论使用哪个创建RandomAccessFile对象,都要求提供两种信息:一个作为数据源的文件,以文件名字符串或文件对象的方式表述;另一个是访问模式字符串,它规定了RandomAccessFile对象可以用何种方式打开和访问指定的文件。
23
10.2 文件输入/输出 随机存取文件 访问模式字符串mode有两种取值:“r”代表了以只读方式打开文件;“rw”代表以读写方式打开文件,这时用一个对象就可以同时实现读写两种操作。 创建RandomAccessFile对象时,可能产生两种异常:当指定的文件不存在时,系统将抛出FileNotFoundException;若试图用读写方式打开只读属性的文件或出现了其他输入、输出错误,则会抛出IOException异常。 下面是创建RandomAccessFile对象例子: File File1=new File ("File1.txt" ); RandomAccessFile MyRa=new RandomAccessFile (File1, "rw" );
24
10.2 文件输入/输出 10.2.3 随机存取文件 2.对文件位置指针的操作
10.2 文件输入/输出 随机存取文件 2.对文件位置指针的操作 RandomAccessFile实现的是随机读写,即可以在文件的任意位置执行数据读写,而不一定要从前向后操作。要实现这样的功能,必须定义文件位置指针和移动这个指针的方法。RandomAccessFile对象的文件位置指针遵循如下的规律: (1)新建RandomAccessFile对象的文件位置指针位于文件的开头处。 (2)每次读写操作之后,文件位置指针都相应后移读写的字节数。 (3)利用getPointer()方法可获取当前文件位置指针从文件头算起的绝对位置。 (4)利用seek()方法可以移动文件位置指针。 public void seek(long pos); 该方法将文件位置指针移动到参数pos指定的从文件头算起的绝对位置处。 (5)length()方法将返回文件的字节长度。 public long length(); 根据length()方法返回的文件长度和位置指针相比较,可以判断是否读到了文件尾。
25
10.2 文件输入/输出 随机存取文件 3.读操作 与DataInputStream相似,RandomAccessFile类也实现了DataInput接口,即它也可以用多种方法分别读取不同类型的数据,具有比FileInputStream更强大的功能。 RandomAccessFile的读方法主要有:readBealoon(),readChar(),readInt(),readLong(),readFloat(),readDouble(),readLine(),readUTF()等。
26
10.2 文件输入/输出 随机存取文件 4.写操作 在实现了DataInput接口的同时,RandomAccessFile类还实现了DataOutput接口,这就使它具有了与DataOutputStream类同样强大的含类型转换的输出功能。 RandomAccessFile类包含的写方法主要有:writeBealoon(),writeChar(),writeInt(),writeLong(),writeFloat(),writeDouble(),writeLine(),writeUTF()等。其中writeUTF()方法可以向文件输出一个字符串对象。 RandomAccessFile类的所有方法都有可能抛出IOException异常,所以利用它实现文件对象操作时应把相关的语句放在try块中,并配上catch块来处理可能产生的异常对象。
Similar presentations