9.1 Java输入输出流
所有的程序语言都提供与本机文件系统交互的方式,Java也不例外。我们将看看Java是怎样处理标准文件输入输出的(包括stdin,stout,stderr)。当你在网络上开发小程序时,你必须注意直接文件输入输出是不安全因素的关键。大多数用户设置他们的浏览器,可让你自由的访问他们的文件系统,但有些不让你访问。当然,如果你开发你内部的应用程序,你也许需要直接访问文件。
标准输入输出Unix的用户,或其他基于命令行系统的用户(如DOS),都知道标准输入输出的含义。标准输入文件是键盘,标准输出文件是你的终端屏幕。标准错误输出文件也指向屏幕,如果有必要,它也可以指向另一个文件以便和正常输出区分。系统类Java通过系统类达到访问标准输入输出的功能。
上面提到的三个文件在这个系统类中实现:Stdin System.in作为InputStream类的一个实例来实现stdin,你可以使用read()和skip(long n)两个成员函数。read()让你从输入中读一个字节,skip(long n)让你在输入中跳过n个字节。Stout System.out作为PrintStream来实现stdout,你可以使用print()和println()两个成员函数。这两个函数支持Java的任意基本类为参数。Stderr System.err同stdout一样实现stderr。象System.out一样,你可以访问PrintStream成员函数。
9.2 标准输入输出例子
这里有一个例子,功能象Unix里的cat或type:
import java.io.*
class myCat{
public void main(String args[])
throws IOException{
int b;
int count = 0;
while ((b = System.in.read()) != -1){
count++;
System.out.print((char)b);
}
System.out.println(); //blank line
System.err.println("counted"+count+"total bytes.");
}
}
9.3 普通输入输出类
除了基本的键盘输入和屏幕输出外,我们还需要联系文件的输入输出。我们将学习下面几个类:
FileInputStream
DataInputStream
FileOutputStream
DataOutputStream
作为参考,再列出一些特定应用的类:
PipedInputStream
BufferedInputStream
PushBackInputStream
StreamTokenizer
PipedOutputStream
BufferedOutputStream
RandomAccessFile
我们不在此讨论这些类,但你可以在JAVA_HOME/src/java/io目录里查看每个类的成员函数定义。
9.4 文件
在我们进行文件操作时,需要知道一些关于文件的信息。File类提供了一些成员函数来操纵文件和获得一些文件的信息。
9.4.1 创建一个新的文件对象
你可用下面三个方法来创建一个新文件对象:
File myFile; myFile = new File("etc/motd");
myFile = new File("/etc","motd"); //more useful if the directory or filename are variables
File myDir = new file("/etc"); myFile = new File(myDir,"motd");
这三种方法取决于你访问文件的方式。
例如,如果你在应用程序里只用一个文件,第一种创建文件的结构是最容易的。但如果你在同一目录里打开数个文件,则第二种或第三种结构更好一些。
9.4.2 文件测试和使用
一旦你创建了一个文件对象,你便可以使用以下成员函数来获得文件相关信息:
文件名
String getName()、String getPath()、String getAbslutePath()、String getParent()、boolean renameTo(File newName)
文件测试
boolean exists()、boolean canWrite()、boolean canRead()、boolean isFile()、boolean isDirectory()、boolean isAbsolute()
一般文件信息
long lastModified()、long length()
目录用法
boolean mkdir()、String[] list()
9.4.3 文件信息获取例子程序
这里是一个独立的显示文件的基本信息的程序,文件通过命令行参数传输:
import java.io.*;
class fileInfo{
File fileToCheck;
public static void main(String args[])
throws IOException{
if (args.length>0){
for (int i=0;i<args.length;i++){
fileToCheck = new File(args[i]);
info(fileToCheck);
}
}else{
System.out.println("No file given.");
}
}
public void info (File f)
throws IOException {
System.out.println("Name: "+f.getName());
System.out.println("Path: "=f.getPath());
if (f.exists()) {
System.out.println("File exists.");
System.out.print((f.canRead() ?" and is Readable":""));
System.out.print((f.cnaWrite()?" and is Writeable":""));
System.out.println(".");
System.out.println("File is " + f.lenght() = " bytes.");
}else{
System.out.println("File does not exist.");
}
}
}
9.5 输入流
 InputStream SequenceInputStream FileInputStream PipedInputStream ByteArrayInputStream FileterInputStream StringBufferInputStream DataInputStream LineNumberInputStream PushbackInputStream BufferedInputStream 有好几个类是专门用来处理文件输入的。
下面是文件输入类的层次结构:
9.5.1 FileInputStream对象
FileInputStream典型地表示一种顺序访问的文本文件。通过使用FileInputStream你可以访问文件的一个字节、几个字节或整个文件。
9.5.2 打开FileInputStream
为一个文件打开输入流FileInputStream,你必须将文件名或文件对象传送给结构:
FileInput Stream myFileStream;
myFileStream = new FileInputStream ( "/etc/motd");
你还可以象下边这样从FileInputStream里读文件信息:
File myFile;
FileInputSteam myFileStream;
myFile = new File("/etc/motd");
myFileStream = new FileInputStream(myFile);
一旦FileInputStream输入流打开,你就可以从里面读取信息了。read()成员函数有以下几种选项:
int read() //reads one byte //return -1 at end of stream
int read(byte b[]) //fills entire array,if possible //returns number of bytes read //returns -1 if end of stream is reached
int read(byte b[],int offset, int len) //reads len bytes into b starting at b[offset] //Returns number of bytes read, //or -1 if end of stream is reached.
9.5.3关闭FileInputStream
当你完成一个文件的操作,你可选两种方法关闭它:显式关闭和隐式关闭。隐式关闭是自动垃圾回收时的功能,显式关闭如下: myFileStream.close();。
9.6 例 程:显示一个文件
如果文件的访问权限足够,你可以在TextArea对象里显示文件内容。下面是显示文件的程序片断:
FileInputStream fis;
TextArea ta;
public vod init(){
byte b[] = new byte [1024];
int I; //make it big enough or wait until you //know the size of the file String s;
try {
fis = new FileInputStream("/etc/motd");
}catch(FileNotFoundException e){
/*do something appropriate */
}
try {
I= fis.read(b);
}catch(IOException e){
 /* do something appropriate */
}
s = new String(b, 0);
ta = new TextArea(s,5,40);
add (ta);
}
9.7 DataInputStreams
DataInputStreams与FileInputStreams差不多。Data流可以直接读任意一种变量类型,如浮点数,整数和字符等。一般来说,对二进制文件使用DataInputStream流。
9.7.1 打开和关闭DataInputStreams
打开和关闭DataInputStreams对象时,其方法与FileInputStreams相同:
DataInputStreams myDataStream;
FileInputStreams myFileStream; //get a file handle
myFileStream = new FileInputStream("/usr/db/stock.dbf"); //open,or "chain" a data input file
myDataStream = new DataOutputStream(myFileStream); //Now we can use both input streams to access our file //j(If we want to...)
myFileStream.read(b);
I = myDataStrea.readInt(); //close the data friel explicityly //Always close the "topmost" file stream
myDataStream.close();
myFileStream.close();
9.7.2 读DataInputStreams
当你从DataInputStreams流里访问文件时,你可以使用与FileInputStream流相同的成员函数read()。但你也可以使用其他访问方法来读取不同种类的数据:byte readByte()、int readUnsignedByte()、short readShort()、int readUnsighedShort()、char readChar()、int readInt、long readLong()、float readFloat()、double readDouble()、String readLine()
以上每一个成员函数都读取相应的数据对象。象String readLine()成员函数,你可使用\n,\r,\r\n,或EOF作为字符串结束符。读一个长整型,例如:long serialNo; ... serialNo = myDataStream.readLong();
9.8 URL输入流
除了基本文件访问外,Java还提供了通过网络使用URL访问对象的功能。在下面这个例子里,我们用getDocumentBase()成员函数并显式指定URL对象来访问声音和图象。
String imageFile = new String ("images/Duke/T1.gif");
images[0] = getImage(getDocumentBase(),imageFile();
如果我们愿意,可以直接使用URL:
URL imageSource;
imageSource = new URL("http://555-1212.com/~info");
images[0] = getImage(imageSource,"Duke/T1.gif");
我们可以为相应的URL打开输入流。例如,下面的程序里包括一个数据文件:
InputStream is;
byte buffer[] = new byte[24];
is = new URL(getDocumentBase(),dataname).openStream();
现在我们可以使用is,就象使用FileInputStream对象一样:is.read(buffer.0,buffer.length);
注意:有些用户设置了他们的浏览器安全属性,可以不让你的程序访问他们的文件。
9.9 OutputStreams
上面我们谈到了读数据,那么如何实现写数据呢?象输入流一样,输出流也有类似的层次结构:OutputStream FileOutputStream PipedOutputStream ByteArrayOutputStream FilterOutputStream DataOutputStream PrintStream BufferedOutputStream 我们将分析FileOutputStream和DataOutputStream类来完成我们碰到的输出流问题。其它的输出流包含了更多的信息和成员函数。象输入流的源文件一样,这些文件在$JAVA_HOME/src/java/io目录下。
9.9.1 FileOutputStream类
FileOutputStream对象用于向一个文本文件写数据。象输入文件一样,你得先打开这个文件后才能写这个文件。
9.9.2 打开一个FileOutputStream对象
要打开一个FileOutputStream对象,象打开一个输入流一样,你可以将字符串或文件对象作为参数:
FileOutputStream myFileStream;
myFileStream = new FileOutputStream("/etc/motd");
象输入流一样,你也可这样使用:
File myFile;
FileOutputStream myFileStream;
myFile = new File("/etc/motd");
myFileStream = new FileOutputStream(myFile);
9.9.3 写入一个流
一旦文件被打开,你便可以使用write()函数向文件里写一些数据。就象输入流的read()函数一样,你可有三种方法:
void write(int b);//writes out one byte
void write(byte b[]);//writes out entire array
void write (byte b[],int offset,int length);//write out length bytes of b[],starting at b[offset]
9.9.4 关闭一个FileOutputStream对象
关闭输出流和关闭输入流方法一样,你可以使用显式方法:myFileStream.close();你也可以让系统自动关闭它。
9.10 例子:存储信息
下面有一个程序,让用户输入一些姓名和电话号码。每一个姓名和号码将加在文件里。用户通过点“Done"按钮来告诉系统整个列表已输入完毕。一旦用户输入完整个列表,程序将创建一个输出文件并显示或打印出来。例如:
555-1212,Tom 123-456-7890,Peggy L. 234-5678,Marc 234-5678,Ron 876-4321,Beth&Brian 33.1.42.45.70,Jean-Marc
下面是程序的源代码:
import java.io.*; //Phones.java //A simple database creation program
class Phones{
static FileOutputStream fos;
public static final int lineLength = 81;
public static void main(String args[])
throws IOExciption {
byte[] phone = new byte[lineLength];
byte[] name = new byte[lineLenght];
int I;
fos = new FileOutputStream("phone.numbers");
while (true){
System.err.println("Enter a name (enter ’done’ to quit)");
readLine(name);
if ("done".equalsIgnoreCase(new String(name,0,0,4))){
break;
}
System.err.println("Enter the phone number");
readLine(phone);
for ( i=0;phone[i]!= 0;i++) {
fos.write(phone[i]);
}
fos.write(’,’);
for (i=0;name[i]!= 0;I++) {
fos.write(name[i]);
}
fos.write(’\n’);
}
fos.close();
}
private static void readLine(byte line[])
throws IOException {
int i=0,b=0;
while ((i<lineLengh-1))&&((b=System.ini.read())!=’\n’)){
line[i++] = (byte)b;
}
line[i]=(byte) 0;
}
}
9.11 BufferedOutput流
如果你处理的数据量很多,或向文件写很多次小数据,你可以使用一个BufferedOutput流。BufferedOutput流提供和FileOutputStream类同样的写操作方法,但所有输出全部存放在一个缓冲区里。当你填满缓冲区,它将一次性写入磁盘。或者你主动将缓冲区写入磁盘。
9.11.1 创建BufferedOutput流
如果要创建一个BufferedOutput流,首先需要一个FileOutput流。然后将缓冲区链接到FileOutput流:
FileOutputStream myFileStream;
BufferedOutputStream myBufferStream; //get a file handle
myFileStream = new FileOutputStream("/usr/db/stock.dbf"); //chain a buffered output stream
myBufferSSstream = new BufferedOutputStream(myFileStream);
9.11.2 更新和关闭BufferedOutput流
和普通FileOutput流一样,向BufferedOutput流里的每一次写操作和写入磁盘操作并不是一一对应的。要想在程序结束之前将缓冲区里的数据写入磁盘,除非填满缓冲区,否则只有显式调用flush()函数:
//force left-over data to disk
myBufferStream.flush();
//close the data file explicitly
myBufferStream.close();
//Always close the "topmost" file stream
myFileStream.close();
9.12 DataOutput流
和DataInputStream对应,Java还提供了DataOutput流。使用DataOutput流,我们可以向文件写入二进制数据。
9.12.1 打开和关闭DataOutput流对象
打开和关闭DataOutput流对象与打开、关闭FileOutput流对象方法一样:
DataOutputStream myDataStream;
FileOutputStream myFileStream;
BufferedOutputStream myBufferStream; //get a file handle
mhyFileStream = new FileOutputStream("/usr/db/stock.dbf"); //chain a buffered output stream (for efficiency);
myBufferStream = new BufferedOutputStream(myFileStream); //chain a data output file
myDataStream = new DataOutputStream(myBufferStream); //Now we can use both input streams to access our file //(iiIf we want to ...)
myBufferStream.write(b);
myDataStream.writeInt(i); //close the data file explicitly //Always colse the "topmost" file stream 
myDataStream.close();
myBuffersStream.close();
myFileStream.close();
9.12.2 向DataOutput流写数据
FileOutput流里的write()函数各种方法都适用于DataOutput流。你还可以看到DataInput流的类似函数方法:
void writeBoolean (boolean v)
void writeByte (int v)
void writeShort (int v)
void writeChar (int v)
void writeInt (int v)
void writeFloat (float v)
void writeDouble (double v)
void writeBytes (string s)
void writeChars (string s)
对字符串来说,有两种选择:byte和char。记住byte是8位数据而char是16位数据。如果你想利用Unicode字符的优点,你应使用writeChars()函数。
9.12.3 输出记数
在使用二进制数据输出时常用的另外一个函数是size()。这个函数返回写入文件数据的总字节数。你也可用size()函数将数据文件分成四字节为单位的块,例如:
...
int bytesLeft = myDataStream.size()%4;
for (int I = 0; I< bytesLeft; I++) {
myDataStrea.write(0);
}
...
9.13 随机访问文件
我们读文件常常不是从头至尾顺序读的。你也许想将一文本文件当作一个数据库,读完一个记录后,跳到另一个记录,它们在文件的不同地方。Java提供了RandomAccessFile类让你操作这种类型的输入输出。
9.13.1 创建随机访问文件
打开随机访问文件有两种方法:
用文件名 myRAFile = new RandomAccessFile(String name,String mode);
用文件对象 myRAFile = new RandomAccessFile(File file,String mode);
mode参数决定了访问文件的权限,如只读’r’或读写’wr’等。例如,我们打开一个数据库更新数据:
RandomAccessFile myRAFile;
myRAFile = new RandomAccessFile("/usr/db/stock.dbf","rw");
9.13.2 访问信息
RandomAccessFile对象的读写操作和DataInput/DataOutput对象的操作方式一样。你可以使用在DataInputStream和DataOutputStream里出现的所有read()和write()函数。还有几个函数帮助你在文件里移动指针:
long getFilePointer(); 返回当前指针
void seek(long pos); 将文件指针定位到一个绝对地址。地址是相对于文件头的偏移量。地址0表示文件的开头。
long length(); 返回文件的长度。地址"length()"表示文件的结尾。
9.13.3 增加信息
你可以使用随机访问文件来设置成增加信息模式:
myRAFile = new RandomAccessFile("/tmp/java.log","rw");
myRAFile.seek(myRAFile.length()); //Any subsequent write()s will be appended to the file
9.13.4 追加信息例子
下面是一个在已存在文件后面追加字符串的例子:
import java.io.IOException;
import java.io.RandomAccessFile;
class raTest {
public static void main(String args[])
throws IOException {
RandomAccessFile myFAFile;
String s = "Information to Append\nHi mom!\n"; //open our random access file
myRAFile = new RandomAccessFile("/tmp/java.log","rw"); //move to the end of the file 
myRAFile.seek(myRAFile.length()); //Start appending!
myRAFile.writeBytes(s);
myRAFile.close();
}
}
本章小结
1. Java通过系统类达到访问标准输入输出的功能。
2. 你可以创建、读、写文件。

来自:http://www.linux8.net/html/java/2005-11/16/21_38_02_170.html