您的位置:首页 > 理论基础 > 计算机网络

Java的基本I/O(输入/输出)系统copy from (http://blog.sina.com.cn/s/blog_5ec67df20100d6ao.html)

2011-01-19 13:38 573 查看
o包支持Java的基本I/O(输入/输出)系统,包括文件的输入/输出。对输入/输出的支持是来源于Java的内核API库,而不是语言关键字。

一、输入/输出基础

很多实际的Java应用程序不是基于文本的控制台程序。尽管基于文本的程序作为教学实例是很
出色的,它们无法胜任JAVA在实际中的重要应用。Java对外设输入/输出的支持也是有限的,并且用起来有些笨拙——甚至是在简单的例子程序中。基于文
本的控制台输入/输出对于Java程序并不是十分重要。
Java 提供了与文件和网络相关的强大的和灵活的输入/输出支持,Java的输入/输出系统是紧密相连并且是具有一致性的。

1.1 流的概念

Java程序通过流来完成输入/输出。流是生产或消费信息的抽象。流通过Java的输入/输
出系统与物理设备链接。尽管与它们链接的物理设备不尽相同,所有流的行为具有同样的方式。这样,相同的输入/输出类和方法适用于所有类型的外部设备。这意
味着一个输入流能够抽象多种不同类型的输入:从磁盘文件,从键盘或从网络套接字。同样,一个输出流可以输出到控制台,磁盘文件或相连的网络。流是处理输入
/输出的一个洁净的方法,例如它不需要代码理解键盘和网络的不同。Java中流的实现是在java.io包定义的类层次结构内部的。

1.2 字节流和字符流

要使用流类,必须导入Java.io包。Java 2
定义了两种类型的流:字节类和字符类。字节流(byte
stream)为处理字节的输入和输出提供了方便的方法。例如使用字节流读取或书写二进制数据。字符流(character
stream)为字符的输入和输出处理提供了方便。它们采用了统一的编码标准,因而可以国际化。在某些场合,字符流比字节流更有效。在最底层,所有的输入
/输出都是字节形式的。基于字符的流只为处理字符提供方便有效的方法。下面是对字节流和字符流的概述。

1.2.1 字节流类

字节流由两个类层次结构定义。在顶层有两个抽象类:InputStream 和 OutputStream。每个抽象类都有多个具体的子类,这些子类对不同的外设进行处理,例如磁盘文件,网络连接,甚至是内存缓冲区。字节流类显示于表1-1中。
表1-1 字节流类
流类
含义
BufferedInputStream

BufferedOutputStream

ByteArrayInputStream

ByteArrayOutputStream

DataInputStream

DataOutputStream

FileInputStream

FileOutputStream

FilterInputStream

FilterOutputStream

InputStream

OutputStream

PipedInputStream

PipedOutputStream

PrintStream

PushbackInputStream

RandomAccessFile

SequenceInputStream
缓冲输入流

缓冲输出流

从字节数组读取的输入流

向字节数组写入的输出流

包含读取Java标准数据类型方法的输入流

包含编写Java标准数据类型方法的输出流

读取文件的输入流

写文件的输出流

实现InputStream

实现OutputStream

描述流输入的抽象类

描述流输出的抽象类

输入管道

输出管道

包含print()和println()的输出流

支持向输入流返回一个字节的单字节的“unget”的输入流

支持随机文件输入/输出

两个或两个以上顺序读取的输入流组成的输入流
抽象类InputStream 和
OutputStream定义了实现其他流类的关键方法。最重要的两种方法是read()和write(),它们分别对数据的字节进行读写。两种方法都在
InputStream 和OutputStream中被定义为抽象方法。它们被派生的流类重载。

1.2.2 字符流类

字符流类由两个类层次结构定义。顶层有两个抽象类:Reader和Writer。这些抽象类处理统一编码的字符流。Java中这些类含有多个具体的子类。字符流类如表1-2所示。
表1-2 字符流的输入/输出类
流类
含义
BufferedReader

BufferedWriter

CharArrayReader

CharArrayWriter

FileReader

FileWriter

FilterReader

FilterWriter

InputStreamReader

LineNumberReader

OutputStreamWriter

PipedReader

PipedWriter

PrintWriter

PushbackReader

Reader

StringReader

StringWriter

Writer
缓冲输入字符流

缓冲输出字符流

从字符数组读取数据的输入流

向字符数组写数据的输出流

读取文件的输入流

写文件的输出流

过滤读

过滤写

把字节转换成字符的输入流

计算行数的输入流

把字符转换成字节的输出流

输入管道

输出管道

包含print()和println()的输出流

允许字符返回到输入流的输入流

描述字符流输入的抽象类

读取字符串的输入流

写字符串的输出流

描述字符流输出的抽象类
抽象类Reader和Writer定义了几个实现其他流类的关键方法。其中两个最重要的是read()和write(),它们分别进行字符数据的读和写。这些方法被派生流类重载。

1.3 预定义流

所有的Java程序自动导入java.lang包。该包定义了一个名为System的类,该
类封装了运行时环境的多个方面。System 同时包含三个预定义的流变量,in,out和err。这些成员在System中是被定义成public
和static型的,这意味着它们可以不引用特定的System对象而被用于程序的其他部分。
System.out是标准的输出流。默认情况下,它是一个控制台。System.in是标
准输入,默认情况下,它指的是键盘。System.err指的是标准错误流,它默认是控制台。然而,这些流可以重定向到任何兼容的输入/输出设备。
System.in
是inputStream的对象;System.out和System.err是PrintStream的对象。它们都是字节流,尽管它们用来读写外设的
字符。但可以用基于字符的流来包装它们。

二、读取控制台输入

在Java
1.0中,完成控制台输入的惟一途径是字节流,使用该方法的老代码依然存在。今天,运用字节流读取控制台输入在技术上仍是可行的,但这样做需要用到不被赞
成的方法,这种做法不值得推荐。Java 2中读取控制台输入的首选方法是字符流,它使程序容易符合国际标准并且易于维护。
Java没有像标准C的函数scanf()或C++输入操作符那样的统一的控制台输入方法。
Java中,控制台输入由从System.in读取数据来完成。为获得属于控制台的字符流,在BufferedReader对象中包装
System.in。BufferedReader 支持缓冲输入流。它最常见的构造函数如下:
BufferedReader(Reader inputReader)
这里,inputReader是链接被创建的BufferedReader实例的流。
Reader是一个抽象类。它的一个具体的子类是InputStreamReader,该子类把字节转换成字符。为获得链接System.in的一个
InputStreamReader的对象,用下面的构造函数:
InputStreamReader(InputStream inputStream)
因为System .in引用了InputStream 类型的对象,它可以用于inputStream。综上所述,下面的一行代码创建了与键盘相连的BufferedReader对象。
BufferedReader br = new BufferedReader(new

InputStreamReader(System.in));
当该语句执行后,br是通过System.in生成的链接控制台的字符流。

2.1 读取字符

从BufferedReader读取字符,用read()。这里所用的read()版本如下:
int read( ) throws IOException
该方法每次执行都从输入流读取一个字符然后以整型返回。当遇到流的末尾时它返回-1。可以看到,它要引发一个IOException异常。下面的例程演示了read()方法,从控制台读取字符直到用户键入“q”:
// Use a BufferedReader to read characters from the console.

import java.io.*;

class BRRead {

public static void main(String args[])

throws IOException

{

char c;

BufferedReader br = new

BufferedReader(new InputStreamReader(System.in));

System.out.println("Enter characters, 'q' to quit.");

// read characters

do {

c = (char) br.read();

System.out.println(c);

} while(c != 'q');

}

}
下面是程序运行:
Enter characters, 'q' to quit.

123abcq

1

2

3

a

b

c

q

2.2 读取字符串

从键盘读取字符串,使用readLine()。它是BufferedReader 类的成员。它的通常形式如下:
String readLine( ) throws IOException
它返回一个String对象。下面的例子阐述了BufferedReader类和readLine()方法;程序读取和显示文本的行直到键入“stop”:
// Read a string from console using a BufferedReader.

import java.io.*;

class BRReadLines {

public static void main(String args[])

throws IOException

{

// create a BufferedReader using System.in

BufferedReader br = new BufferedReader(new

InputStreamReader(System.in));

String str;

System.out.println("Enter lines of text.");

System.out.println("Enter 'stop' to quit.");

do {

str = br.readLine();

System.out.println(str);

} while(!str.equals("stop"));

}

}
下面的例程生成了一个小文本编辑器。它创建了一个String对象的数组,然后依行读取文本,把文本每一行存入数组。它将读取到100行或直到按“stop”才停止。该例运用一个BufferedReader类来从控制台读取数据。
// A tiny editor.

import java.io.*;

class TinyEdit {

public static void main(String args[])

throws IOException

{

// create a BufferedReader using System.in

BufferedReader br = new BufferedReader(new

InputStreamReader(System.in));

String str[] = new String[100];

System.out.println("Enter lines of text.");

System.out.println("Enter 'stop' to quit.");

for(int i=0; i<100; i++) {

str[i] = br.readLine();

if(str[i].equals("stop")) break;

}

System.out.println("/nHere is your file:");

// display the lines

for(int i=0; i<100; i++) {

if(str[i].equals("stop")) break;

System.out.println(str[i]);

}

}

}
下面是输出部分:
Enter lines of text.

Enter ‘stop’ to quit.

This is line one.

This is line two.

Java makes working with strings easy.

Just create String objects.

stop

Here is your file:

This is line one.

This is line two.

Java makes working with strings easy.

Just create String objects.

三、向控制台写输出

控制台输出由print( ) 和 println(
)来完成最为简单。这两种方法由PrintStream(System.out引用的对象类型)定义。尽管System.out是一个字节流,用它作为简
单程序的输出是可行的。因为PrintStream是从OutputStream派生的输出流,它同样实现低级方法write(),write()可用来
向控制台写数据。PrintStream 定义的write( )的最简单的形式如下:
void write(int byteval)
该方法按照byteval指定的数目向文件写字节。尽管byteval 定义成整数,但只有低位的8个字节被写入。下面的短例用 write()向屏幕输出字符“A”,然后是新的行。
// Demonstrate System.out.write().

class WriteDemo {

public static void main(String args[]) {

int b;

b = 'A';

System.out.write(b);

System.out.write('/n');

}

}
一般不常用write()来完成向控制台的输出(尽管这样做在某些场合非常有用),因为print()和println() 更容易用。

四、PrintWriter类

尽管Java允许用System.out向控制台写数据,但建议仅用在调试程序时或在例程
中。对于实际的程序,Java推荐的向控制台写数据的方法是用PrintWriter流。PrintWriter是基于字符的类。用基于字符类向控制台写
数据使程序更为国际化。PrintWriter定义了多个构造函数,这里所用到的一个如下:
PrintWriter(OutputStream outputStream, boolean flushOnNewline)
outputStream是OutputStream类的对象,flushOnNewline控制Java是否在println()方法被调用时刷新输出流。如果flushOnNewline为true,刷新自动发生,若为false,则不发生。
PrintWriter支持所有类型(包括Object)的print(
)和println(
)方法,这样,就可以像用System.out那样用这些方法。如果遇到不同类型的情况,PrintWriter方法调用对象的toString()方法
并打印结果。用PrintWriter向外设写数据,指定输出流为System.out并在每一新行后刷新流。例如这行代码创建了与控制台输出相连的
PrintWriter类。
PrintWriter pw = new PrintWriter(System.out, true);
下面的应用程序说明了用PrintWriter处理控制台输出的方法:
// Demonstrate PrintWriter

import java.io.*;

public class PrintWriterDemo {

public static void main(String args[]) {

PrintWriter pw = new PrintWriter(System.out, true);

pw.println("This is a string");

int i = -7;

pw.println(i);

double d = 4.5e-7;

pw.println(d);

}

}
该程序的输出如下:
This is a string

-7

4.5E-7

五、文件的读写

Java提供了一系列的读写文件的类和方法。在Java中,所有的文件都是字节形式的。Java提供从文件读写字节的方法。而且,Java允许在字符形式的对象中使用字节文件流。
两个最常用的流类是FileInputStream和FileOutputStream,它
们生成与文件链接的字节流。为打开文件,只需创建这些类中某一个类的一个对象,在构造函数中以参数形式指定文件的名称。这两个类都支持其他形式的重载构造
函数。下面是这里将要用到的形式:
FileInputStream(String fileName) throws FileNotFoundException

FileOutputStream(String fileName) throws FileNotFoundException
fileName指定需要打开的文件名。当创建了一个输入流而文件不存在时,引发
FileNotFoundException异常。对于输出流,如果文件不能生成,则引发FileNotFoundException异常。如果一个输出
文件被打开,所有原先存在的同名的文件被破坏。注意:在早期的Java版本中,当输出文件不能创建时FileOutputStream()引发一个
IOException异常。这在Java 2中有所修改。当对文件的操作结束后,需要调用close(
)来关闭文件。该方法在FileInputStream和FileOutputStream中都有定义。如下:
void close( ) throws IOException
为读文件,可以使用在FileInputStream中定义的read( )方法。这里用到的如下:
int read( ) throws IOException
该方法每次被调用,它仅从文件中读取一个字节并将该字节以整数形式返回。当读到文件尾
时,read(
)返回-1。该方法可以引发IOException异常。下面的程序用read()来输入和显示文本文件的内容,该文件名以命令行形式指定。注意
try/catch块处理程序运行时可能发生的两个错误——未找到指定的文件或用户忘记包括文件名了。
import java.io.*;

class ShowFile {

public static void main(String args[])

throws IOException

{

int i;

FileInputStream fin;

try {

fin = new FileInputStream(args[0]);

} catch(FileNotFoundException e) {

System.out.println("File Not Found");

return;

} catch(ArrayIndexOutOfBoundsException e) {

System.out.println("Usage: ShowFile File");

return;

}

// read characters until EOF is encountered

do {

i = fin.read();

if(i != -1) System.out.print((char) i);

} while(i != -1);

fin.close();

}

}
向文件中写数据,需用FileOutputStream定义的write()方法。它的最简单形式如下:
void write(int byteval) throws IOException
该方法按照byteval指定的数目向文件写入字节。尽管byteval作为整数声明,但仅低8位字节可以写入文件。如果在写的过程中出现问题,一个IOException被引发。下面的例子用write()拷贝一个文本文件:
import java.io.*;

class CopyFile {

public static void main(String args[])

throws IOException

{

int i;

FileInputStream fin;

FileOutputStream fout;

try {

// open input file

try {

fin = new FileInputStream(args[0]);

} catch(FileNotFoundException e) {

System.out.println("Input File Not Found");

return;

}

// open output file

try {

fout = new FileOutputStream(args[1]);

} catch(FileNotFoundException e) {

System.out.println("Error Opening Output File");

return;

}

} catch(ArrayIndexOutOfBoundsException e) {

System.out.println("Usage: CopyFile From To");

return;

}

// Copy File

try {

do {

i = fin.read();

if(i != -1) fout.write(i);

} while(i != -1);

} catch(IOException e) {

System.out.println("File Error");

}

fin.close();

fout.close();

}

}
注意本程序中和前面ShowFile程序中处理潜在输入/输出错误的方法。不像其他的计算机
语言,包括C和C++,这些语言用错误代码报告文件错误,而Java用异常处理机制。这样不仅是文件处理更为简洁,而且使Java正在执行输入时容易区分
是文件出错还是EOF条件问题。在C/C++中,很多输入函数在出错时和到达文件结尾时返回相同的值(也就是说,在C/C++中,EOF情况与输入错误情
况映射相同)。这通常意味着程序员必须还要编写特殊程序语句来判定究竟是哪种事件发生。Java中,错误通过异常引发,而不是通过read()的返回值。
这样,当read( )返回-1时,它仅表示一点:遇到了文件的结尾。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐