`
249009188
  • 浏览: 45216 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

java IO类

 
阅读更多

Java的核心库java.io提供了全面的IO接口,包括:文件读写、标准设备输出等。Java中IO是以流为基础进行输入输出的,所有数据被串行化写入输出流,或者从输入流读入。

在项目开发中,IO是非常基础的部分,在面试当中经常出现。

对于初学者而言,IO部分是容易忽略的内容,求职者一定要掌握该知识点。

10.3.1  了解Java的IO类

面试例题28:下面关于System.out的说法哪个正确?

请选择正确的答案。

(a)System.out是1个PrintStream。

(b)System.out是1个OutputStream。

(c)System.out是1个FilterOutputStream。

(d)System.out是1个PrintStream。

(e)System.out在异常时,将抛出IOException。

考点:考查求职者对Java语言的IO处理的掌握。

出现频率:★★★★

解析

IO(Input/Output)是计算机输出/输出的接口。Java的核心库java.io提供了全面的IO接口,包括文件读写、标准设备输出等。Java中IO是以流为基础进行输入输出的,所有数据被串行化写入输出流,或者从输入流读入。此外,Java也对块传输提供支持,在核心库java.nio中采用的便是块IO。

注意:流IO的好处是简单易用,缺点是效率较低。块IO效率很高,但编程比较复杂。

Java的IO模型设计非常优秀,它使用Decorator模式,用户可以动态装配不同功能的Stream,以便获得需要的功能。例如,需要一个具有缓冲的文件输入流,则应当组合使用FileInputStream和BufferedInputStream。

Java的IO体系分Input/Output和Reader/Writer两类,区别在于Reader/Writer在读写文本时能自动转换内码。基本上,所有的IO类都是配对的,即有XxxInput就有一个对应的XxxOutput。

Java的输入/输出操作是基于数据流(Stream)的,有序的字节或者字符通过一个通信信道从源地址传送到目的地址。Java支持两个数据流:InputStream和OutputStream。这两个数据流又可以分为许多子类来完成IO功能。Java 1.1版本正式加入了Reader和Writer两个类,支持Java IO的国际化标准,并通过国际化字符编码(Unicode)将文本存储起来。

Reader类类似于InputStream类,它是输入类层次中的基础,Reader支持16位的Unicode字符输出,而InputStream只支持8位字符输出。Reader类有如下所示的6个直接子类。

BufferedReader:该类支持缓冲字符输入,它的子类LineNumberReader支持缓冲输入并能够追踪行数。

CharArrayReader:该类能够从一个字符缓冲区中读入一个字符输入流。

FilterReader:是一个抽象类,是过滤的字符输入数据流的基础。

InputStreamReader:该类可以把字节输入流转换为字符输入流,子类FileReader用来读取字符文件。

PipedReader:该类用来从一个管道中读取字符。

StringReader:该类从一个字符串中读取字符。

面试例题28中,System.out是PrintStream的一个子类,而PrintStream继承了FilterOutputStream类,FilterOutputStream类继承了OutputStream类。PrintStream对象并没有抛出IOException异常。

答案:(a)(b)(c)。

10.3.2  使用InputStream和OutputStream

面试例题29:哪个语句可以建立文件"file.txt"的字节输入流?

请选择正确的答案。

(a)InputStream in=new InputStream("file.txt");

(b)InputStream in=new FileReader("file.txt");

(c)FileInputStream in=new FileOutputStream("file.txt");

(d)FileInputStream in=new FileInputStream("file.txt");

考点:考查求职者对InputStream和OutputStream的掌握。

出现频率:★★★★

解析

1.InputStream类的常见方法

public abstract int read() throws IOException:从当前输入流中读取数据的下一个字节。返回的字节值是在0~255范围内的一个int型数。如果已读到流的末尾,没有再可读的字节时,则返回-1。该方法将一直阻塞,直到有输入数据,检测到了数据流尾或抛出异常。子类必须提供当前方法的一个实现。

public int read(byte b[]) throws IOException:将当前输入流中b.length个字节的数据读到一个字节数组中。本方法用b.0和b.length3个参数调用具有3个参数的read()方法。

public int read(byte b[],int off,int len) throws IOException:将输入流中len个字节数据读入一个字节数组中。这个方法将保持阻塞直到有输入数据可用。如果参数b为null,则将抛出NullPointerException。本方法使用零个参数的read()方法,一次读取一个字节,并将之放入该数组。鼓励子类提供一个更有效的当前方法的实现。

public long skip(long n) throws IOException:从当前输入流中跳过并丢弃n个字节数据,返回实际跳过的字节数。
public void close() throws IOException:关闭当前输入流,并释放与它相关的任一系统资源。InputStream的close()方法不做任何事。

public synchronized void mark(int readlimit):在该输入流中标记当前位置。后续调用reset()方法重新将流定位于最后标记位置,以便后续能重新读取相同字节。readlimit参数给出当前输入流在标记位置变为非法前允许读取的字节数。
public synchronized void reset() throws IOException:将该输入流重新定位到上一次调用mark方法时标记的位置。InputStream的reset()方法抛出一个IOException,因为输入流默认不支持mark()和reset()方法。可以通过markSupport()方法测试输入流是否支持mark()和reset()方法。

public boolean markSupported():测试该输入流是否支持mark()和reset()方法。InputStream的markSupported方法返回false。

2.OutputStream类的常见方法

public abstract void write(int b) throws IOException:将指定字节写入当前输出流。OutputStream的子类必须提供此方法的一个实现。

public void write(byte b[]) throws IOException:将指定的字节数组中b.length字节,写到当前输出流。OutputStream的write方法,用3个参数b、0和b.length调用具有3个参数的write()方法。

public void write(byte b[],int off,int len) throws IOException:将指定字节数组中从off开始的len个字节写到当前输出流。OutputStream的write()方法调用一个参数的write()方法,输出每个字节。子类应覆盖这个方法,并提供更有效的实现方法。

public void flush() throws IOException:刷新当前输出流,将任何缓冲输出的字节输出到此流中。

public void close() throws IOException:关闭当前输出流,且释放与它相关的任一系统资源。

面试例题39中需要注意的是"字节流",所以(a)是正确的选项。

答案:(a)。

 

 

10.3.3  常用的文件操作类(1)

面试例题30:选择正确的文件操作。

当前文件系统中已经存在了文件file.txt,该文件包涵有ASCII文本,代码片段如下:

try {
File f = new File("file.txt");
outputStream out = new FileOutputStream(f, true);
}
catch (IOException) {}   

结果是什么?

(a)代码不能编译。

(b)代码可以编译并运行,对该文件不会有改变。

(c)代码可以编译并运行,并将该文件的长度设置为0。

(d)抛出异常,因为该文件没有关闭。

(e)代码可以编译运行,并从文件系统中删除该文件。

考点:考查求职者对Java的文件输入输出相关类的熟悉程度。

出现频率:★★★★

解析

Java为文件的操作提供了丰富的类,这里主要介绍几个经常用到的类。

1.File类

File类的实例表示主机文件系统中的文件。一个文件能通过一个路径名指定,此路径名可以是一条绝对路径名,也可以是一条相对于当前工作目录的相对路径名。路径名必须遵循主机平台的命名约定。

File类提供了一种抽象方式,以与机器无关的方式处理有关文件和路径名的大多数复杂问题。

注意:不管何时使用一个文件名或路径,均假定使用主机的文件命名规范。

File类的构造函数如下所示。

File(File,String):创建一个File实例,表示指定路径指定名称的文件。

File(String):创建一个File实例,表示路径名是指定路径参数的文件。

File(String,String):创建一个File实例,它的路径名是指定的路径名后跟分隔符字符和name参数。

File类的常用方法如下所示。

canRead():测试应用程序是否能从指定的文件中进行读取。

canWrite():测试应用程序是否能写当前文件。

delete():删除当前对象指定的文件。

equals(Object):比较该对象和指定对象。

exists():测试当前File是否存在。

getAbsolutePath():返回由该对象表示的文件的绝对路径名。

getCanonicalPath():返回当前File对象的路径名的规范格式。

getName():返回表示当前对象的文件名。

getParent():返回当前File对象路径名的父路径名,如果此名没有父路径则为null。

getPath():返回表示当前对象的路径名。

hashCode():计算此文件的一个哈希码。

isAbsolute():测试当前File对象表示的文件是否是一个绝对路径名。

isDirectory():测试当前File对象表示的文件是否是一个路径。

isFile():测试当前File对象表示的文件是否是一个"普通"文件。

lastModified():返回当前File对象表示的文件最后修改的时间。

length():返回当前File对象表示的文件长度。

list():返回当前File对象指定的路径文件列表。

list(FilenameFilter):返回当前File对象指定的目录中满足指定过滤器的文件列表。

mkdir():创建一个目录,它的路径名由当前File对象指定。

mkdirs():创建一个目录,它的路径名由当前File对象指定,包括任一必须的父路径。

renameTo(File):将当前File对象指定的文件更名为给定参数File指定的路径名。

toString():返回当前对象的字符串表示。

2.FileInputStream

文件输入流是一个从File或FileDescriptor读取数据的输入流。输入流以字节为单位(非unicode),二进制数据与编码无关,不存在乱码问题。

构造器如下所示。

FileInputStream(File):创建一个输入文件流,从指定的 File 对象读取数据。

FileInputStream(FileDescriptor):创建一个输入文件流,从指定的文件描述器读取数据。

FileInputStream(String):创建一个输入文件流,从指定名称的文件读取数据。

常见的方法介绍如下。

available():返回从当前文件输入流中可无阻塞读取的字节数。

close():关闭当前文件输入流,并释放与它相关的任一系统资源。

finalize():当这个文件输入流不再有引用时,确保调用它的close()方法。

getFD():返回与当前流相关的不透明的文件描述符。

read():从当前输入流中读取一个字节数据。

read(byte[]):将当前输入流中b.length个字节数据读到一个字节数组中。

read(byte[],int,int):将输入流中len个字节数据读入一个字节数组中。

skip(long):跳过并删除输入流中的n字节数据。

说明:File类与FileInputStream类的区别在于流类关注的是文件内容,而File类关注的是文件在磁盘上的存储。File不属于文件流,只能代表一个文件或是目录的路径名而已。

如果处理文件或者目录名,就应该使用File对象,而不是字符串。例如,File类的equals方法知道一些文件系统对大小写是敏感的,目录尾的"/"字符无关紧要。

 

 

10.3.3  常用的文件操作类(2)

3.FileReader

FileReader是读取字符文件的方便类。这个类的构造器假定默认字符编码和默认字节缓冲尺寸是正确的。为了指定这些值,可创建FileInputStream的一个InputStreamReader对象。

FileReader类是InputStreamReader类的子类,所有方法都从父类InputStreamReader中继承而来。

FileReader类和FileInputStream类的区别如下。

FileInputStream是以字节流方式读取,FileReader是把文件转换为字符流读入。InputStream提供的是字节流的读取,而非文本读取,这是和Reader类的根本区别。用Reader读取出来的是char数组或者String,使用InputStream读取出来的是byte数组。

Reader类及其子类提供的字符流读取char(16位,unicode编码),inputStream及其子类提供字节流读取byte(8位),所以FileReader类是将文件按字符流的方式读取,FileInputStream则按字节流的方式读取文件。InputStreamReader可以将读取如stream转换成字符流方式,是reader和stream之间的桥梁。

最初Java是不支持对文本文件的处理的,为了弥补这个缺憾而引入了Reader和Writer两个类。

FileInputStream类以二进制输入/输出,I/O速度快且效率高,但是它的read()方法读到的是一个字节(二进制数据),很不利于人们阅读。而FileReader类弥补了这个缺陷,可以以文本格式输入或输出,非常方便。例如,可以使用while((ch=filereader.read())!=-1)循环来读取文件;可以使用BufferedReader的readLine()方法一行一行的读取文本。

InputStreamReader和BufferedReader。其中最重要的类是InputStreamReader,它是字节转换为字符的桥梁。编程者可以在构造器重指定编码的方式,如果不指定的话将采用底层操作系统的默认编码方式,例如GBK等。

FileReader与InputStreamReader涉及编码转换(指定编码方式或者采用操作系统默认编码)时,可能在不同的平台上出现乱码现象。而FileInputStream以二进制方式处理,不会出现乱码现象。

4.FileOutputStream

文件输出流是向File或FileDescriptor输出数据的一个输出流。

构造器如下所示。

FileOutputStream(File):创建一个文件输出流,向指定的File对象输出数据。

FileOutputStream(FileDescriptor):创建一个文件输出流,向指定的文件描述器输出数据。

FileOutputStream(String):创建一个文件输出流,向指定名称的文件输出数据。

FileOutputStream(String,boolean):创建一个向具有指定名称的文件中写入数据的输出文件流。如果第2个参数为true,则将字节写入文件末尾处,而不是写入文件开始处。以下情况将则抛出FileNotFoundException异常:该文件存在,但它是一个目录,而不是一个常规文件;该文件不存在,但无法创建它;因为其他某些原因而无法打开。

常见的方法如下所示。

close():关闭当前文件输出流,并释放与它相关的任一系统资源。

finalize():当这个文件输出流不再有引用时,确保调用它的close()方法。

getFD():返回与当前流相关的文件描述符。

write(byte[]):将指定字节数组中b.length字节写入当前文件输出流。

write(byte[],int,int):将指定字节数组中以偏移量off开始的len个字节写入当前文件输出流。

write(int):将指定字节写入当前文件输出流。

5.FilterWriter

输出过滤后的字符流的抽象类。常见的方法如下所示。

close():关闭流。

flush():刷新流。

write(char[],int,int):将若干字符写入一个数组中。

write(int):写入单一字符。

write(String,int,int):写入一个字符串的某部分。

FilterWriter和FileOutputStream的区别类似于FileReader类和FileInputStream类的区别,都是字节流和字符流的区别。

面试例题30中,关键是需要求职者掌握FileOutputStream类的构造方法,特别是第2个参数的含义,true说明是打开文件,并在末尾的位置添加内容,并没有破坏已经存在文件的内容。

答案:(b)。

面试例题31:哪个方法能够获得file.txt文件的父路径?

Which gets name of the parent directory file "file.txt"?(下面哪个方法能够获得file.txt文件的父路径?)

(a)String name=File.getParentName("file.txt");

(b)String name=(new File("file.txt")).getParent();

(c)String name=(new File("file.txt")).getParentName();

(d)String name=(new File("file.txt")).getParentFile();

(e)Directory dir=(new File("file.txt")).getParentDir();

String name=dir.getName();

考点:考查求职者对Java的文件输入输出相关类的熟悉程度。

出现频率:★★★★

解析

读者可以参考File类的相关方法介绍。

答案:(b)。

面试例题32:将"hello"字符写入文件file.txt的末尾。

下面哪个选项可以将"hello"字符写入文件file.txt的末尾?

(a)OutputStream out= new FileOutputStream ("file.txt"); Out.writeBytes ("hello");

(b)OutputStream os= new FileOutputStream ("file.txt", true); DataOutputStream out = new DataOutputStream(os); out.writeBytes ("hello");

(c)OutputStream os= new FileOutputStream ("file.txt"); DataOutputStream out = new DataOutputStream(os); out.writeBytes ("hello");

(d)OutputStream os= new OutputStream ("file.txt", true); DataOutputStream out = new DataOutputStream(os); out.writeBytes ("hello");

考点:考查求职者对Java的文件输入输出相关类的熟悉程度。

出现频率:★★★★

解析

(a)使用默认的文件写入方式,重新写入文件,即清除已经存在的文件内容,不符合题目要求;(c)同(a)是一样的;(d)的OutputStream并没有上述的构造方法。所以(b)是正确的。

答案:(b)。

 

 

10.3.4  掌握过滤IO类(1)

面试例题33:哪个类是FilterOutputStream类构造器的合法参数?

FilterOutputStream类是BufferedOutputStream类、DataOutputStream类和PrintStream类的父类。哪个类是FilterOutputStream类构造器的合法参数?

(a)InputStream

(b)OutputStream

(c)File

(d)RandomAccessFile

(e)StreamTokenizer

考点:考查求职者对Java的过滤IO相关类的掌握。

出现频率:★★★

解析

IO过滤器根据程序的需要来调整数据流,这些过滤器介于一个输入数据流和输出数据流之间,并可以对从输入数据流中传送到输出中的字节进行特殊处理

1.FilterInputStream

这个类是所有输入流过滤器类的父类。这些流位于一个已存在的输入流(基本的输入流)的上层,但是提供了附加功能。

类FilterInputStream简单地覆盖了InputStream的所有方法,使之用于向基本输入流发出各种请求。FilterInputStream的子类可以进一步覆盖这些方法中的某些方法,也可提供额外的方法和域。

以下所示是常见的方法和构造器。

FilterInputStream(InputStream):在指定的输入流之上,创建一个输入流过滤器。

available():返回从当前输入流中可无阻塞读取的字节数。

close():关闭当前输入流,并释放与它相关的任一系统资源。

mark(int):在该输入流中标记当前位置。

markSupported():测试该输入流是否支持mark和reset方法。

read():从当前输入流中读取数据的下一个字节。

read(byte[]):将当前输入流中byte.length个字节数据读到一个字节数组中。

read(byte[],int,int):将输入流中len个字节数据读入一个字节数组中。

reset():将该输入流重新定位到上次调用mark方法时标记的位置。

skip(long):跳过并放弃输入流中的n个字节数据。

FilterInputStream类含有下列子类:BufferedInputStream、CheckedInputStream、DataInputStream、DigestInputStream、InflaterInputStream、LineNumberInputStream、PushbackInputStream。

2.FilterOutputStream

这个类是所有过滤器输出流的父类。这些流位于一个现存的输出流(基本的输出流)的上层,但是提供了附加功能。

类FilterOutputStream简单地覆盖了OutputStream的所有方法,使之用于向基本输出流发出各种请求。FilterOutputStream的子类可以进一步覆盖这些方法中的某些方法,也可提供额外的方法和域。

构造器和常见的方法如下所示。

FilterOutputStream(OutputStream):创建一个输出流过滤器,建立在指定输入流的上面。

close():关闭当前输出流,且释放与它相关的任一系统资源。

flush():刷新当前输出流,将任何缓冲输出的字节输出到此流中。

write(byte[]):将b.length个字节写入当前输出流。

write(byte[],int,int):将指定byte数组中从off开始的len个字节,写到当前输出流。

write(int):将指定的byte写到当前输出流。

FilterOutputStream类有如下子类:BufferedOutputStream、CheckedOutputStream、DataOutputStream、DeflaterOutputStream、DigestOutputStream、PrintStream。

 

 

10.3.4  掌握过滤IO类(2)

3.DataInputStream

数据输入流可以使一个应用程序以与机器无关的方式从基本输入流中读取Java的基本数据类型。应用程序使用一个数据输出流输出数据,以后可使用一个数据输入流读入。

数据输入流和数据输出流以稍加修订的UTF-8格式表示Unicode字符串。该类的主要方法如下所示。

DataInputStream(InputStream):创建一个新的数据输入流,从指定输入流中读取数据。

read(byte[]):将当前数据输入流中byte.length个字节数据读到一个字节数组中。

read(byte[],int,int):将当前数据输入流中len个字节数据读入一个字节数组中。

readBoolean():从当前数据输入流中读取一个boolean值。

readByte():从当前数据输入流中读取一个有符号的8位数。

readChar():从当前数据输入流中读取一个Unicode字符。

readDouble():从当前数据输入流中读取一个double值。

readFloat():从当前数据输入流中读取一个float值。

readFully(byte[]):从当前数据输入流中读取b.length个字节到该字节数组。

readFully(byte[],int,int):从当前数据输入流中恰好读取len个字节到该字节数组中。

readInt():从当前数据输入流中读取一个有符号的32位整数。

readLine():从当前数据输入流中读取文本的下一行。不推荐使用该方法。

readLong():从当前数据输入流中读取一个有符号的64位整数。

readShort():从当前数据输入流中读取一个有符号的16位数。

readUnsignedByte():从当前数据输入流中读取一个无符号的8位数。

readUnsignedShort():从当前数据输入流中读取一个无符号的16位数。

readUTF():从当前数据输入流中读取一个已用"修订的UTF-8格式"编码的字符串。

readUTF(DataInput):从指定的数据输入流中读取一个字符串。

skipBytes(int):准确地跳过基本输入流中的n字节。

4.DataOutputStream

数据输出流可以使一个应用程序以简洁的方式将Java基本数据类型写入到一个输出流。随后某个应用程序能使用一个数据输入流读回这些数据。该类常见的方法如下所示。

DataOutputStream(OutputStream):创建一个新的数据输出流,向指定的基本输出流写入数据。

flush():刷新当前数据输出流。

size():返回写入当前数据输出流的字节数。

write(byte[],int,int):将指定的字节数组中从off开始的len个字节,写到基本输出流。

write(int):将指定字节写入基本输出流。

writeBoolean(boolean):将一个boolean值作为一字节值,写入该基本输出流。

writeByte(int):将一个byte值作为一字节值,写入该基本输出流。

writeBytes(String):将此串作为一个字节序列写入该基本输出流。

writeChar(int):将一个char值作为两字节值,写入该基本输出流,高字节优先。

writeChars(String):将此串作为一个字符序列写入该基本输出流。

writeDouble(double):使用类Double中doubleToLongBits()方法,将给定的双精度浮点数转换为long值,然后将它当作一个8字节数写入该基本输出流,高字节优先。

writeFloat(float):使用类Float中floatToIntBits方法,将给定的单精度浮点数转换为int值,然后将它当作一个4字节数写入该基本输出流,高字节位优先。

writeInt(int):将一个int值作为4字节值,写入该基本输出流,高字节优先。

writeLong(long):将一个long值作为8字节值,写入该基本输出流,高字节优先。

writeShort(int):将一个short值作为两字节值,写入该基本输出流,高字节优先。

writeUTF(String):使用独立于机器的UTF-8编码格式,将一个串写入该基本输出流。

5.使用示例

下面给出一个操作文件的示例,该示例写入一组数据,读出并打印出来,示例代码如下:

package ch10;
import java.io.*;
public class MyIo {
public static void main(String[] args) throws IOException {
// 将数据写入某一种载体
DataOutputStream out = new DataOutputStream(new FileOutputStream(
"invoice1.txt"));
// 价格
double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 };
// 数目
int[] units = { 12, 8, 13, 29, 50 };
        // 描述
String[] descs = { "Java T-shirt", "Java Mug", "Duke Juggling Dolls",
"Java Pin", "Java Key Chain" };
        // 向数据过滤流写入主要类型
for (int i = 0; i < prices.length; i++) {
// 写入价格,使用tab隔开数据
out.writeDouble(prices[i]);
out.writeChar('\t');
// 写入数目
out.writeInt(units[i]);
out.writeChar('\t');
// 写入描述,行尾加入换行符
out.writeChars(descs[i]);
out.writeChar('\n');
}
out.close();
        // 将数据读出
DataInputStream in = new DataInputStream(new FileInputStream(
"invoice1.txt"));
        double price;
int unit;
StringBuffer desc;
double total = 0.0;
        try {
// 当文本被全部读出以后会抛出EOFException例外,中断循环
while (true) {
// 读出价格
price = in.readDouble();
// 跳过tab
in.readChar();
// 读出数目
unit = in.readInt();
// 跳过tab
in.readChar();
char chr;
// 读出描述
desc = new StringBuffer();
while ((chr = in.readChar()) != '\n')
desc.append(chr);
System.out.println("You've ordered " + unit + " units of "
+ desc + " at $" + price);
total = total + unit * price;
}
} catch (EOFException e) {
System.out.println("For a TOTAL of: $" + total);
}
in.close();
}
}
运行该示例代码,结果如下:
You've ordered 12 units of Java T-shirt at $19.99
You've ordered 8 units of Java Mug at $9.99
You've ordered 13 units of Duke Juggling Dolls at $15.99
You've ordered 29 units of Java Pin at $3.99
You've ordered 50 units of Java Key Chain at $4.99
For a TOTAL of: $892.8800000000001

面试例题33考查的是FilterOutputStream构造函数的参数,从前面介绍可以看到,该类只有一个合法的构造参数,类型为OutputStream类。

答案:(b)。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics