admin 管理员组

文章数量: 887093


2024年1月10日发(作者:注册登录代码复选框)

第八章 输入/输出处理

输入/输出处理是程序设计中非常重要的一部分,比如从键盘读取数据、从文件中读取数据或向文件中写数据等等,而键盘、监视器、磁盘存储设备都称为输入、输出源。Java把这些不同类型的输入、输出源抽象为流(stream)。

Java程序可以用输入流从一些输入源读数据,用输出流向一些输出源写数据。

Jdk 提供了包,其中包括一系列的类来实现输入/输出处理。从jdk1.1开始,包中的流包括字节流和字符流。

§8.1

输入/输出字节流概述

§8.1.1 I/O字节流的层次结构

在java中,所有的输入流都是从抽象类InputStream继承而来,所有的输出流都是从OutputStream继承而来。以下给出了java语言IO包中输入/输出处理类之间的继承关系。

FileInputStream

InputStream

PipedInputStream

ByteArrayInputStream

SequenceInputStream

FilterInputStream

BufferedInputStream

LineNumberInputStream

PushbackInputStream

DataInputStream

StringBufferInputStream

ObjectInputStream

DataInput

ObjectInput

RandomAccessFile

ObjectOutput

ObjectOutputStream

FileOutputStream

PipedOutputStream

ByteArrayOutputStream

FilterOutputStream

DataOutputStream

BufferedOutputStream

PrintStream

DataOutput

输入、输出字节流的类层次

一、简单的输入、输出流

1. FileInputStream和FileOutputStream:用于本地文件系统的文件读写。

2. PipedInputStream和PipedOutputStream:用于完成管道的输入和输出。管道用于将一个程序(或线程或代码块)的输出引导进另一个程序(或线程或代码块)的输入,所有PipedInputStream必须连接到一个PipedOutputStream所有PipedOutputStream必须连接到一个PipedInputStream。

3. ByteArrayInputStream和ByteArrayOutputStream:读写内存数据。

4. SequenceInputStream:用于将多个输入流连接到一个输出流。

5. StringBufferInputStream:用于读取StringBuffer类可变字符串中的数据。

二、过滤流

1. DataInputStream和DataOutputStream:用一种与机器无关的格式读写java语言的基本数据类型。

2. BufferedInputStream和BufferedOutputStream:在读写数据的同时缓存数据,从而减少数据源的访问,提高了运行效率。

3. LineNumberInputStream:不仅可以实现读取数据操作,同时可以记录读取的行数。

4. PushbackInputStream:具有一个单字节的缓冲区,利用该缓冲区可以在读取数据的同时预先取得下一个字符。

5. PringStream:提供便利的打印方法的输出流。

三、其它类

1. File:用于描述本地文件系统中的一个文件或目录。用户可以为本地文件系统中的一个文件或目录创建一个File对象。

2. FileDescriptor:用于描述本地文件系统中的一个文件或目录的句柄(或描述符)

3. RandomAccessFile:用于描述一个随机存取文件。

4. StreamTokenizer:用于对一个流中的内容进行解析。一般用于对文本文件进行文法或词法分析,例如可以用它分析一个java源文件,形成变量名,操作符等等。

5. DataInput和DataOutput:这两种接口描述了能用一种与机器无关的格式读写java语言的基本数据类型的流。DataInputStream,DataOutputStream和RandomAccessFile类实现了这两个接口。

6. FileNameFilter:用于文件名查找模式的匹配。

§8.1.2 InputStream和OutputStream类

这两个类都是抽象类,它继承于类。

1.InputStream

◇ 从流中读取数据:

int read( ); //读取一个字节,返回值为所读的字节

int read( byte b[ ] ); //读取多个字节,放置到字节数组b中,通常读取的字节数量为b的长度,返回值为实际读取的字节的数量

int read( byte b[ ], int off, int len ); //读取len个字节,放置到以下标off开始字节数组b中,返回值为实际读取的字节的数量

int available( ); //返回值为流中尚未读取的字节的数量

long skip( long n ); //读指针跳过n个字节不读,返回值为实际跳过的字节数量

◇ 关闭流:

close( ); //流操作完毕后必须关闭

◇ 使用输入流中的标记:

void mark( int readlimit ); //记录当前读指针所在位置,readlimit表示读指针读出readlimit个字节后所标记的指针位置才失效

void reset( ); //把读指针重新指向用mark方法所记录的位置

boolean markSupported( ); //当前的流是否支持读指针的记录功能

有关每个方法的使用,详见java API。

2.OutputStream

◇ 输出数据:

void write( int b ); //往流中写一个字节b

void write( byte b[ ] ); //往流中写一个字节数组b

void write( byte b[ ], int off, int len ); //把字节数组b中从下标off开始,长度为len的字节写入流中

◇ flush( ) //刷空输出流,并输出所有被缓存的字节

由于某些流支持缓存功能,该方法将把缓存中所有内容强制输出到流中。

◇ 关闭流:

close( ); //流操作完毕后必须关闭

§8.1.3 I/O中的异常

进行I/O操作时可能会产生I/O例外,属于非运行时例外,应该在程序中处理。如:FileNotFoundException, EOFException, IOException

§8.2

文件处理

包中提供的文件处理的类有:File、FileInputStream、FileOutputStream、FileDescriptor、RandomAccessFile以及接口FileNameFilter。

§8.2.1 文件描述

一、File类

1. File类:File类提供了一种与平台无关的方式来管理文件和目录的方法。通过File类提供的方法,可以得到有关文件和目录的描述信息,还可以建立,删除目录文件,改变文件和目录的名称等,但File类不能访问文件的内容。

2. File类中常用的几种方法:

1) 文件对象的生成:有三个构造方法可以生成一个文件对象或一个目录对象。

a) public File(String pathname)

b) public File(String parentStr,String childStr)

c) public File(File parentStr,String childStr)

说明:这三种方法只是生成一个文件对象,但没有生成真正的文件,如要生成实实在在

的文件,就需要调用createNewFile()方法。mkdir()

例子:

import .*;

public class CreateFile{

}

运行后查看结果

2)文件名的处理和属性测试P104、P105

File类中提供的有关文件名处理的方法有:

a) String getName()

b) String getPath()

public static void main(String[] args)

{

}

File dirObj=new File("e:file");

File fileObj1=new File("e:file","");

File fileObj2=new File("");

File fileObj3=new File("");

File fileObj4=new File("","e:");//这条语句有问题

n(fileObj2);

try{

();

}catch(SecurityException e){

}

try{

NewFile();

NewFile();

NewFile();

NewFile();

}catch(IOException e){

}

c) String getAbsolutePath()

d) String getParent()

e)public boolean renameTo(File newName) throws IOException

f) int compareTo(File pathname) //按照字典序比较两个文件对象的路径的大小

g) boolean isAbsolute() //用于测试文件对象的路径是不是绝对路径

File类中提供的有关文件属性测试的方法有:

a) boolean isFile()

b) boolean isDirectory()

c) boolean Exists() //测试当前文件对象指示的文件是否存在

d) boolean canRead() //测试当前文件对象指示的文件是否可以读

e) boolean canWrite() //测试当前文件对象指示的文件是否可以写

f) boolean setReadOnly() //将当前文件对象指示的文件设置为只读

g) public long length() throws IOException //获得当前文件的长度,以字节为单位

h) public long lastModified() throws IOException

例子:上面方法的使用

import .*;

public class CreateFile{

try{

();

public static void main(String[] args)

{

File dirObj=new File("e:file");

File fileObj1=new File("e:file","");

File fileObj2=new File("e:");

File fileObj3=new File("");

File fileObj4=new File("e:");

}catch(SecurityException e){

}

try{

}

NewFile();

NewFile();

NewFile();

NewFile();

}catch(IOException e){

boolean pathAbsolute=lute();

n(pathAbsolute); //jieguo: true

n(fileObj1); //jieguo: e:

n(fileObj2); //jieguo: e:

n(e()); //jieguo:

n(h()); //jieguo: e:

n(oluteFile()); //jieguo: e:

n(ent()); //jieguo: e:file

n();

n(eTo(fileObj2)); //jieguo: -1

n();

n(()); //jieguo: true

n(d()); //jieguo: true

n(te()); //jieguo: true

boolean fileRead=dOnly();

n(fileRead); //jieguo: true

n(d()); //jieguo: true

n(te()); //jieguo: false

n();

boolean boolVar2=To(fileObj4);

n(boolVar2); //jieguo: false

n(e()); //jieguo:

n(e()); //jieguo:

}

3)文件操作

a) public boolean mkdir() throws IOException

b) public boolean mkdirs() throws IOException

c) public boolean createNewFile()

d) boolean delete()

e) void deleteOnExit()

f) String list()

g) public String[] list(FilenameFilter filter) throws IOException

h) public Boolean hashCode() //计算文件的哈希吗

I) public Boolean equals(Object obj) //将this对象和指定对象进行比较

j) public String toString() //返回一个描述this对象的字符串描述

例子1:上面g)的使用

import .*;

public class CreateFile{

public static void main(String[] args)

{

File dirObj=new File("e:file");

File fileObj1=new File("e:file","");

File fileObj3=new File("e:");

try{

();

}

}catch(SecurityException e){

}

try{

NewFile();

NewFile();

}catch(IOException e){

}

FilterClass1 filterobj1=new FilterClass1("txt");

String[] filesobj1=(filterobj1);

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

{ n(filesobj1[i]);

}

}

}

class FilterClass1 implements FilenameFilter{

}

例子2:g)的使用

import .*; //引入包中所有的类

public class FileFilterTest{

public static void main(String args[]){

File dir=new File("d:ex"); //用File 对象表示一个目录

Filter filter=new Filter("java"); //生成一个名为java的过滤器

n("list java files in directory "+dir);

String files[]=(filter); //列出目录dir下,文件后缀名为java的所有文件

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

File f=new File(dir,files[i]); //为目录dir 下的文件或目录创建一个File 对象

String fileExtent;

FilterClass1(String extentobj){

}

public boolean accept(File dir,String name){

}

return th("."+fileExtent);

fileExtent=extentobj;

if(()) //如果该对象为后缀为java的文件, 则打印文件名

n("file "+f);

else

n("sub directory "+f ); //如果是目录则打印目录名

}

}

}

class Filter implements FilenameFilter{

String extent;

Filter(String extent){

=extent;

}

public boolean accept(File dir,String name){

return th("."+extent); //返回文件的后缀名

}

}

§8.2.2 文件的顺序访问

类FileInputStream和FileOutputStream用来进行文件I/O处理,由它们所提供的方法可以打开本地主机上的文件,并进行顺序的读/写。例如,下列的语句段是顺序读取文件名为test的文件里的内容,并显示在控制台上面,直到文件结束为止。

import .*;

public class shiyan{

public static void main(String[] args)

{

FileInputStream fis;

try{

fis=new FileInputStream("e:");

n("content of is:");

int b;

}

}

while((b=())!=-1)

{

}

n(b);

}catch(FileNotFoundException e){

n(e);

}catch(IOException e){

}

n(e);

类FileInputStream和FileOutputStream用来进行文件输入/输出处理,在这两个类中,提供了打开本地主机上文件以及进行顺序读写的方法。

一、FileInputStream类用来生成一个文件输入流,文件输入流可以由一个文件描述符或文件名来构造,以实现文件的访问。

FileInputStream类的结构如下:

Public class FileInputStream extends InputStream{

Public FileInputStream(String name) throws FileNotFoundException;

//用指定的与系统相关的文件名name创建一个输入文件。

Public FileInputStream(File file) throws FileNotFoundException;

//用指定的文件对象file创建一个输入文件

public FileInputStream(int fd) throws IOException;

//用指定的与系统相关的文件描述符fd创建一个输入文件。

Public int read() throws IOException;

//读取一个字节的数据。该方法将一直阻塞到输入有效数据。返回读取的字节,如遇到流结束符号则返回-1。

Public int read(byte b[]) throws IOException;

//将数据读到一个字节数组b中。该方法将一直阻塞到输入有效数据。返回值为实际读入的字节数,如遇到流结束符号则返回-1。

Public int read(byte b[],int off,int len) throws IOException;

//将数据读到一个字节数组b中(从off位置开始存放)。该方法将一直阻塞到输入有效数据。返回值为实际读入的字节数,如遇到流结束符号则返回-1。

Public long skip(long n) throws IOException;

//跳过输入的n个字节。返回值为实际跳过的字节数。

Public int available() throws IOException;

//返回值为可以无阻塞读入的字节数

public void close() throws IOException;

//关闭输入流。要释放任何与该流有关的资源,必须调用该方法。

public final int getFD()

//返回与该流有关的文件描述符

protected void finalize() throws IOException;

//当流不再使用时,关闭它

二、FileOutputStream类用来生成一个文件输出流,文件输出流可以由一个文件描述符或文件名来构造,以实现文件的访问。

FileOutputStream类的结构如下:

Public class FileOutputStream extends OutputStream{

Public FileOutputStream(String name) throws FileNotFoundException;

//用指定的与系统相关的文件名name创建一个输出文件。

Public FileOutputStream(File file) throws FileNotFoundException;

//用指定的文件对象file创建一个输出文件

public FileOutputStream(int fd) throws IOException;

//用指定的与系统相关的文件描述符fd创建一个输出文件。

Public void write(int b) throws IOException;

//写出一个字节的数据b。该方法将一直阻塞到字节b已实际写出

Public void write(byte b[]) throws IOException;

//写出一个字节数组。该方法将一直阻塞到所有字节(个字节数据)已实际写出

public void write(byte[] b,int off,int len) throws IOException;

//写出一个字节数组的部分数据(b中从off位置开始的len个字节)。该方法将一直阻塞到所

有字节(len个字节数据)已实际写出

public void close() throws IOException;

//关闭输出流。要释放任何与该流有关的资源,必须调用该方法。

public final int getFD()

//返回与该流有关的文件描述符

protected void finalize() throws IOException;

//当该流不再使用时,关闭它

例子1:FileInputStream和FileOutputStream类使用的例子

import .*;

public class FileSeqAccess{

}

}

}

public static void main(String args[])

{

File fileobj=new File("e:");

FileInputStream inobj;

FileOutputStream outobj;

FileCopy classobj;

try{

NewFile();

inobj=new FileInputStream("e:");

outobj=new FileOutputStream("e:");;

n("*****************");

n("the content of ");

classobj=new FileCopy(inobj,outobj);

}catch(FileNotFoundException e){

n(e);

}catch(IOException e){

n(e);

class FileCopy{

}

说明:文件的输入、输出流的程序设计比较简单。首先,必须通过构造方法打开文件,其次进行文件的读写,最后关闭文件。

例子2:FileInputStream类使用的例子

import .*;

class lizi1{

public static void main(String args[])

{

File fileObj=new File("e:");

try{

FileInputStream fis1=new FileInputStream(fileObj);

FileCopy(FileInputStream inStr,FileOutputStream outStr)

{

}

int len;

byte[] buf=new byte[12];

try{

while((len=(buf,0,12))!=-1)

{

}

String copyStr=new String(buf);

n(copyStr);

(buf,0,len);

}catch(IOException e)

{

}

n("error:"+e);

n(());

byte[] buf=new byte[4];

while(((buf))!=-1)

{

n(ble());

String s=new String(buf);

n(s);

}

}catch(FileNotFoundException e){

}catch(IOException e){}

}

}

例子3:FileInputStream类使用的例子

import putStream;

import ;

import tFoundException;

import ption;

class lizi1{

public static void main(String args[])

{

if(!=1) //测试命令行参数是否正确

{

}

File file=new File(args[0]); //构造args[0]的File对象

try

{

FileInputStream in=new FileInputStream(file); //利用file构造文件输入流

int len;

while((len=())>-1)

{

n("Usage:java Main");

(-1);

}

}

}

if(!e((char)len)) //输出除空格外的所有内容

{

}

((char)len);

(); //关闭文件

(); //强制输出缓冲的数据显示在屏幕上

}catch(FileNotFoundException e){

n(file+"is not found");

}catch(IOException e){

}

tackTrace();

例子4:FileInputStream类的使用

import putStream;

import tFoundException;

import ption;

class lizi1{

public static void main(String args[])

{

if(!=1)

{

}

try

{ //下面构造文件输入流对象in和in2,注意两个构造方法不同

FileInputStream in=new FileInputStream(args[0]);

FileInputStream in2=new FileInputStream(());

n("Usage:java Main");

(-1);

}

}

int avail=ble(); //获得文件的大小

(args[0]+":"+avail+"bytes"); //显示文件的大小

n(";skipped"+(avail)+"bytes"); //文件指针跳到文件末尾

//下面测试文件是否可以读入数据

int len;

while((len=())>-1)

{

}

();

();

((char)len);

}catch(FileNotFoundException e){

n(args[0]+"is not found");

}catch(IOException e){

}

tackTrace();

例子5 FileOutputStream类的使用

import tputStream;

import ption;

class lizi1{

public static void main(String args[])

{

if(!=1)

{

}

n("Usage:java Main");

(-1);

}

try

{

FileOutputStream out=new FileOutputStream(args[0]);

FileOutputStream out2=new FileOutputStream(());

String str="I am a good student.n";

byte[] buf=new byte[()];

es(0,(),buf,0);

(buf); //把buf的内容写出到文件中

(buf); //把buf的内容再次写出到文件中

(); //关闭文件,同时关闭了out和out2输出流

}

}catch(IOException e){

}

tackTrace();

§8.2.3 文件的随机访问

对于InputStream 和OutputStream 来说,它们的实例都是顺序访问流,也就是说,只能对文件进行顺序地读/写。随机访问文件则允许对文件内容进行随机读/写。在java中,类RandomAccessFile 提供了随机访问文件的方法。类RandomAccessFile的声明为:

public class RandomAccessFile extends Object implements DataInput, DataOutput

在java中,RandomAccessFile类提供了随机访问文件的支持,该类实现了DataInput和DataOutput接口,可以用与机器无关的格式读写java的基本数据类型。

RandomAccessFile的构造方法有:

1) public RandomAccessFile(String neme,String mode) throws IOException

//用指定的文件名name和模式mode创建一个随机存取文件。如果mode为r表示只读,如果mode为rw表示读写

2) public RandomAccessFile(int fd) throws IOException

//用指定的与系统相关的文件描述符fd创建一个随机存取文件

3) public RandomAccessFile(File file,String mode) throws IOException

//用指定的文件对象file和模式mode创建一个随机存取文件

下面是RandomAccessFile类中提供的一些文件随机访问方法。

4) long getFilePointer() //得到当前文件指针的位置

5) void seek(long pos) //将文件指针移动到参数指定的位置

6) int skipBytes(int n) //将文件指针向前移动n个字节的位置

7) String readLine() //从当前文件指针位置读取文件中的一行,此行由‘/n’或EOF结尾。

8) Void writeBytes(String s) //将字符串s写入文件中

9)Public int read() throws IOException;

//读取一个字节的数据。该方法将一直阻塞到输入有效数据。返回读取的字节,如遇到流结束符号则返回-1。

10)Public int read(byte b[]) throws IOException;

//将数据读到一个字节数组b中。该方法将一直阻塞到输入有效数据。返回值为实际读入的字节数,如遇到流结束符号则返回-1。

11)Public int read(byte b[],int off,int len) throws IOException;

//将数据读到一个字节数组b中(读入至多len个字节,从off位置开始存放)。该方法将一直阻塞到输入有效数据。返回值为实际读入的字节数,如遇到流结束符号则返回-1。

12)public final void readFully(byte[] b) throws IOException

13) public final void readFully(byte b[],int off,int len) throws IOException

14) Public void write(int b) throws IOException;

//写出一个字节的数据b。该方法将一直阻塞到字节b已实际写出

15) Public void write(byte b[]) throws IOException;

//写出一个字节数组。该方法将一直阻塞到所有字节(个字节数据)已实际写出

16) public void write(byte[] b,int off,int len) throws IOException;

//写出一个字节数组的部分数据(b中从off位置开始的len个字节)。该方法将一直阻塞到所有字节(len个字节数据)已实际写出

17) public long length() throws IOException //返回文件的长度

18) public void close() throws IOException //关闭文件。

19)public final Boolean readBoolean() throws IOException //读入一个布尔量

20)public final byte readByte() throws IOException

21) public final int readUnsignedByte() throws IOException // 读入一个8比特的无符号字节型数据

22)public final short readShort() throws IOException

23) public final int readUnsignedShort() throws IOException

24) public final char readChar() throws IOException

25) public final int readInt() throws IOException

26) public final long readLong() throws IOException

27) public final float readFloat() throws IOException

28) public final double readDouble() throws IOException

29) public final String readUTF() throws IOException

//读入一个UTF格式的字符串

30) public final void writeBoolean(Boolean v) throws IOException

//写出一个布尔量v

31) public final void writeByte(int v) throws IOException

32) public final void writeShort(int v) throws IOException

33) public final void writeBytes(String s) throws IOException

// 以字节的形式写出一个字符串s

34) public final void writeChars(String s) throws IOException

35) public final void writeUTF(String str) throws IOException

//写出一个UTF格式的字符串

说明:从RandomAccessFile类的结构可以看出,它除了支持基本数据类型的输入、输出外,还有seek()、getFilePointer()和skipBytes()方法支持文件的随机访问。

例子1:RandomAccessFile类的使用

import .*;

public class FileRadAccess{

public static void main(String args[])

{

String readStr,tempStr;

int fileLine=0;

long pointerLast1=0,pointerLast2=0;

try

{

RandomAccessFile fileobj1=new RandomAccessFile("e:","rw");

while(ne()!=null)

fileLine++;

n(fileLine);

pointerLast1=ePointer();

n(pointerLast1);

for(int i=0;i

{

}

(i*3);

readStr=ne();

n(readStr);

}catch(IOException e){

try

{

RandomAccessFile fileobj2=new RandomAccessFile("e:","rw");

byte buf[]=new byte[1024];

(pointerLast1);

ytes("rn"+"******hello*****"+"rn");

(0);

ne();

ne();

pointerLast2=ePointer();

n(pointerLast2);

}

}

(buf);

tempStr=new String(buf);

(pointerLast2);

ytes("aaaaaa"+"rn");

ytes(tempStr);

}catch(IOException e){

}

}

例子2:RandomAccessFile类的使用

import .*;

class lizi1{

public static void main(String args[])

{

try

{

RandomAccessFile raf=new RandomAccessFile("e:","rw");

char a='a';

byte b=2;

String c="abc";

short d=4;

byte[] b2={'a','b','c'};

long file_start=ePointer();

n(file_start);

(b);

(b2,0,);

oolean(true);

har(a);

ytes(c);

hars(c);

ouble(123.345);

loat(345.32f);

nt(345);

ong(554L);

hort(d);

TF(c);

TF("abcn");

(b);

hort(d);

n("Length of file:"+());

(file_start);

/* b2=new byte[1];

b=te();

n(b);

(b2);

n("Byte[0]:"+(char)b2[0]);

(b2,0,);

n("Byte[0]:"+(char)b2[0]);

int ub=signedByte();

n("Unsigned Byte:"+ub);

n("Boolean:"+olean());

a=ar();

n("Char;"+a);

byte[] b3=new byte[3];

lly(b3);

n("readFully:"+(char)b3[0]+(char)b3[1]+(char)b3[2]);

tes(6);

double d1=uble();

float f1=oat();

}

}

int i=t();

long l=ng();

short s=ort();

String str=F();

ub=signedByte();

int us=signedShort();

n("UTF String:"+str);

();*/

}catch(IOException e){

n(e);

}

§8.3

管道流

1)管道是用来将一个程序、线程、代码块的输出连接到另一个程序、线程、代码块的输入。以此实现两者的同步数据传输。

2)管道的输入流作为通信管道的接受端,管道输出流作为通信管道的发送端。

3)在使用管道前,管道输入流和输出流必须进行连接。

4)包中提供了PipedInputStream和PipedOutputStream类作为管道的输入和输出部件。这两个类的构造方法如下:

PipedInputStream()

PipedOutputStream()

PipedInputStream(PipedOutputStream srcStream)

PipedOutputStream(PipedInputStream desStream)

其它几个方法:

public void connect(PipedOutputStream src) throws IOException

//将管道输出流src连接到使用PipedInputStream()构造方法所创建的管道输入流

public void connect(PipedInputStream snk) throws IOException

//将这个管道输出流连接到管道输入流snk上

public synchronized int read() throws IOException

//从管道输出流src中读取一个字节的数据。

Public synchronized int read(byte b[],int off,int len) throws IOException

//将管道输出流中的数据读入到一个字节数组b中(从b的off位置开始存放)。该方法将一直阻塞到输入有效数据。返回值为实际读入的字节数,如遇到流结束符则返回-1。该方法至多读入len个字节的数据。

Public void close() throws IOException

//关闭管道输入流

public void write(int b) throws IOException

//把一个字节的数据写入管道输出流。该方法将一直阻塞到字节b已经实际写出

public void write(byte[],int off,int len) throws IOException

//将字节数组b中的部分数据写入到管道输出流。该方法将一直阻塞到字节数组b中的数据已经实际写出

public void close() throws IOException

例子:p115

import .*;

class PipeStream{

public static void main(String args[])

{

try

{

PipedInputStream inObj=new PipedInputStream();

PipeStream2 classObj=new PipeStream2();

t();

DataInputStream receiverObj=new DataInputStream(inObj);

String readStr;

();

readStr=F();

n(readStr);

}

}

();

();

}catch(IOException e){

}

n(e);

(0);

class PipeStream2{

PipedOutputStream outObj;

DataOutputStream senderObj;

public PipeStream2()

{

outObj=new PipedOutputStream();

}

public void writes()

{

}

public void close()

{

try

try

{

senderObj=new DataOutputStream(outObj);

String writeStr=new String("Hi,glad to meet you!");

TF(writeStr);

}catch(IOException e){

}

n(e);

{();

}catch(IOException e){

}

}

}

例子2:

例子3:

n(e);

§8.4

过滤流

在包中,FilterInputStream和FilterOutputStream类是所有过滤输入流和过滤输出流的父类。他们是抽象类。

过滤流在输入和输出数据的同时,对数据进行处理。

一、DataInputStream和DataOutputstream

这两个类分别实现了接口DataInput和DataOutput,因此可以用与机器无关的方式读写基本数据类型。

(一)DataInputStream类的结构

这个类用来生成一个数据输入流,通过该流,用户可以用与平台无关的方式读取java的基本数据类型。

Public class DataInputStream extends FilterInputStream{

Public DataInputStream(InputStream in);

//创建一个新的DataInputStream,该流从输入流in读取数据。

其它方法参见RandomAccessFile类中用与机器无关的方式读数据的方法

(二)DataOutputStream类的结构

这个类用来创建数据输出流,用户可以用与平台无关的方式将java的基本数据类型写入到流中。

Public class DataOutputStream extends FilterOutputStream{

Protected int written;//目前已经写出的字节数

Public DataOutputStream(OutputStream out);

//在输出流out上创建一个新的DataOutputStream,使DataOutputstream的输出数据能够输出到输出流out中

其它方法参见RandomAccessFile类中用与机器无关的方式写数据的方法

(三)数据输入流和数据输出流是过滤流,因此在构造它们时必须与具体的输入和输出流相连接,然后才能使用其中的方法进行数据的输入和输出。数据输入流和数据输出流主要用于实现基本数据类型的输入和输出。

例子:数据输入流的使用

import .*;

class lizi2{

public static void main(String args[])

{

if(!=1)

{

}

n("Usage:java Main");

(-1);

FileInputStream file_in;

DataInputStream data_in;

try

{

file_in=new FileInputStream(args[0]);

data_in=new DataInputStream(file_in);

n(data_ble());

byte b;

byte[] b2=new byte[1];

b=data_te();

n(b);

data_(b2);

n(char)b2[0]);

data_(b2,0,);

n((char)b2[0]);

int ub=data_signedByte();

n(ub);

n(data_olean());

char a=data_readChar();

n(a);

byte[] b3=new byte[3];

data_lly(b3);

n((char)b3[0]+(char)b3[1]+(char)b3[2]);

data_tes(6); //tiaoguo"abc"

double d1=data_uble();

n(d1);

float f1=data_oat();

n(f1);

int i=data_t();

long l=data_ng();

short s=data_F();

ub=data_signedByte();

int us=data_isignedShort();

n(str);

}catch(IOException e)

n(e);

}

}

}

例子2:数据输出流的使用

import .*;

class lizi3{

public static void main(String args[])

{

if(!=1)

{

}

n("Usage:java Main");

(-1);

FileOutputStream file_out;

DataOutputStream data_out;

try

{

file_out=new FileOutputStream(args[0]);

data_out=new DataOutputStream(file_out);

char a='a';

byte b=123;

String c="abc";

short d=4;

byte[] b2={'a','b','c'};

data_(b);

data_(b2,0,);

data_oolean(true);

data_har(a);

data_ytes(c);

data_hars(c);

data_ouble(134.45);

data_loat(244,44f);

data_nt(22);

data_ong(234l);

data_hort(d);

data_TF(c);

data_TF("abcn");

data_(b);

data_hort(d);

data_();

n(data_());//Size of file written

data_();

}catch(IOException e)

n(e);

}

}

}

例子(课本上):

import .*;

class FilterTest{

public static void main(String args[])

{

File fileObj;

FileOutputStream outStream;

BufferedOutputStream bufOutObj;

DataInputStream dataInObj;

PushbackInputStream pushObj;

try

{

String strObj="How do you do!rn I am glad to meet you!";

byte[] tempBuf;

fileObj=new File("");

if(()==false)

}

{

}

outStream=new FileOutputStream(fileObj);

bufOutObj=new BufferedOutputStream(outStream);

tempBuf=es();

n(tempBuf);

(tempBuf,0,);

();

dataInObj=new DataInputStream(new FileInputStream(fileObj));

n(olean());

int pushData;

pushObj=new PushbackInputStream(new FileInputStream(""));

while((pushData=())!=-1)

{

NewFile();

} if(er((char)pushData))

}

{

}

else

("**");

((char)pushData);

}catch(IOException e){

}

n(e);

§8.4 顺序输入流

包中提供了SequenceInputStream类,用于将多个输入流顺序连接起来,使它们看起来就象一个比较长的流。

顺序输入流提供了把若干个不同的流统一为同一个流的功能。

例子:

import .*;

class SeqTest{

public static void main(String args[])

{

FileInputStream fileStream1,fileStream2;

try

{

String allStr;

fileStream1=new FileInputStream("");

fileStream2=new FileInputStream("");

SequenceInputStream seqStream=new SequenceInputStream(fileStream1,fileStream2);

byte[] bufByte=new byte[512];

while((bufByte,0,512)!=-1)

{

}

String tempStr=new String(bufByte);

n(tempStr);

}catch(FileNotFoundException e){

n("File not found or no permission.");

}catch(IOException e){

}

}

}

n(e);

§8.5 字符流处理

java中提供了处理以16位的Unicode码表示的字符流的类,即以Reader和Writer 为基类派生出的一系列类。 这两个类是抽象类,只是提供了一系列用于字符流处理的接口,不能生成这两个类的实例,只能通过使用由它们派生出来的子类对象来处理字符流。

§8.4.1 Reader和Writer

1.Reader类是处理所有字符流输入类的父类。

◇ 读取字符

public int read() throws IOException; //读取一个字符,返回值为读取的字符

public int read(char cbuf[]) throws IOException; /*读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量*/

public abstract int read(char cbuf[],int off,int len) throws IOException;

/*读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现*/

◇ 标记流

public boolean markSupported(); //判断当前流是否支持做标记

public void mark(int readAheadLimit) throws IOException;

//给当前流作标记,最多支持readAheadLimit个字符的回溯。

public void reset() throws IOException; //将当前流重置到做标记处

◇ 关闭流

public abstract void close() throws IOException;

2. Writer类是处理所有字符流输出类的父类。

◇ 向输出流写入字符

public void write(int c) throws IOException;

//将整型值c的低16位写入输出流

public void write(char cbuf[]) throws IOException;

//将字符数组cbuf[]写入输出流

public abstract void write(char cbuf[],int off,int len) throws IOException;

//将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流

public void write(String str) throws IOException;

//将字符串str中的字符写入输出流

public void write(String str,int off,int len) throws IOException;

//将字符串str 中从索引off开始处的len个字符写入输出流

◇ flush( )

刷空输出流,并输出所有被缓存的字符。

◇ 关闭流

public abstract void close() throws IOException;

§8.4.2 InputStreamReader和OutputStreamWriter

这两个类分别是Reader和Writer类的子类。包中用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介。

◇ 生成流对象

public InputStreamReader(InputStream in);

/*in是字节流,而InputStreamReader是字符流,但是其来源是字节流in,因此InputStreamReader就可以把字节流in转换成字符流处理。/*

public InputStreamReader(InputStream in,String enc) throws UnsupportedEncodingException;

/*enc是编码方式,就是从字节流到字符流进行转换时所采用的编码方式,

例如 ISO8859-1,UTF-8,UTF-16等等*/

public OutputStreamWriter(OutputStream out);

/*out是字节流,而OutputStreamReader是字符流 */

public OutputStreamWriter(OutputStream out,String enc) throws UnsupportedEncodingException; //enc是编码方式

InputStreamReader和OutputStreamWriter的方法:

◇ 读入和写出字符

基本同Reader和Writer。

◇ 获取当前编码方式

public String getEncoding();

◇ 关闭流

public void close() throws IOException;

§8.4.3 BufferedReader和BufferedWriter

为了提高字符流处理的效率,在java语言中,引入了这两个类来对字符流进行块处理。◇ 生成流对象

public BufferedReader(Reader in);

//基于Reader字符输入流in对象生成相应的缓冲流,使用缺省的缓冲区大小

public BufferedReader(Reader in, int sz);

//基于Reader字符输入流in对象生成相应的缓冲流,sz为缓冲区的大小

public BufferedWriter(Writer out);

//基于Writer字符输出流out对象生成相应的缓冲流,使用缺省的缓冲区大小

public BufferedWriter(Writer out, int sz);

//基于Writer字符输出流out对象生成相应的缓冲流,sz为缓冲区的大小

◇ 读入/写出字符

除了Reader和Writer中提供的基本的读写方法外,增加对整行字符的处理。

public String readLine() throws IOException; //读一行字符

public void newLine() throws IOException; //写一行字符

例子1:(课本p120)

import .*;

public class lizi4{

public static void main(String args[]) throws FileNotFoundException,IOException{

String lineStr;

File fileObj;

FileInputStream fileInStream;

InputStreamReader inputReader;

BufferedReader bufReader;

FileOutputStream fileOutStream;

OutputStreamWriter outputWriter;

BufferedWriter bufWriter;

String newStr=new String("Today is 's can go out.");

try

{

}

}

fileObj=new File("");

if(()==false)

{

}

fileOutStream=new FileOutputStream(fileObj);

outputWriter=new OutputStreamWriter(fileOutStream);

bufWriter=new BufferedWriter(outputWriter);

(newStr,0,());

();

();

();

NewFile();

}catch(IOException e){

}

fileInStream=new FileInputStream("");

inputReader=new InputStreamReader(fileInStream);

bufReader=new BufferedReader(inputReader);

n("content of :");

while((lineStr=ne())!=null)

n(lineStr);

();

();

();

n(e);

例子2:(课本p121)

import .*;

public class lizi5{

}

public static void main(String args[])

{

}

n("This is a example about beyboard inputting.");

String strObj="0";

try

{

InputStreamReader inObj;

BufferedReader bufObj;

inObj=new InputStreamReader();

bufObj=new BufferedReader(inObj);

strObj=ne();

n("n="+strObj);

}catch(IOException e){

}

int n=nt(strObj);

int multiNum;

multiNum=n*(n+1)/2;

n("The sum is:"+multiNum);

n("Exception:"+e);

【例4-4】

import .*;

public class NumberInput{

public static void main(String args[]){

try{

InputStreamReader ir;

BufferedReader in;

ir=new InputStreamReader();

//从键盘接收了一个字符串的输入,并创建了一个字符输入流的对象

in=new BufferedReader(ir);

String s=ne();

//从输入流in中读入一行,并将读取的值赋值给字符串变量s

n("Input value is: "+s);

int i = nt(s);//转换成int型

i*=2;

n("Input value changed after doubled: "+i);

}catch(IOException e)

{n(e);}

}

}

查看运行结果

注意:在读取字符流时,如果不是来自于本地的,比如说来自于网络上某处的与本地编码方式不同的机器,那么我们在构造输入流时就不能简单地使用本地缺省的编码方式,否则读出的字符就不正确;为了正确地读出异种机上的字符,我们应该使用下述方式构造输入流对象:

ir = new InputStreamReader(is, "8859_1");

采用ISO 8859_1编码方式,这是一种映射到ASCII码的编码方式,可以在不同平台之间正确转换字符。

§8.6 对象串行化

§8.6.1 对象串行化的定义

1. 什么是串行化

对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力,叫做对象的持续性(persistence)。对象通过写出描述自己状态的数值来记录自己,这个过程叫对象的串行化(Serialization)。

2. 串行化的目的

串行化的目的是为java的运行环境提供一组特性,其主要任务是写出对象实例变量的数值。

§8.6.2 串行化方法

在包中,接口Serializable用来作为实现对象串行化的工具,只有实现了Serializable的类的对象才可以被串行化。

1. 定义一个可串行化对象

public class Student implements Serializable{

int id; //学号

String name; //姓名

int age; //年龄

String department //系别

public Student(int id,String name,int age,String department){

= id;

= name;

= age;

ment = department;

}

}

2. 构造对象的输入/输出流

要串行化一个对象,必须与一定的对象输入/输出流联系起来,通过对象输出流将对象状态保存下来,再通过对象输入流将对象状态恢复。

包中,提供了ObjectInputStream和ObjectOutputStream将数据流功能扩展至可读写对象。在ObjectInputStream中用readObject()方法可以直接读取一个对象,ObjectOutputStream中用writeObject()方法可以直接将对象保存到输出流中。

Student stu=new Student(981036,"Liu Ming",18, "CSD");

FileOutputStream fo=new FileOutputStream("");

//保存对象的状态

ObjectOutputStream so=new ObjectOutputStream(fo);

try{

bject(stu);

();

}catch(IOException e )

{n(e);}

FileInputStream fi=new FileInputStream("");

ObjectInputStream si=new ObjectInputStream(fi);

//恢复对象的状态

try{

stu=(Student)ject();

();

}catch(IOException e )

{n(e);}

在这个例子中,我们首先定义一个类Student,实现了 Serializable接口,然后通过对象输出流的writeObject()方法将Student对象保存到文件中。之后,通过对象输入流的readObject()方法从文件中读出保存下来的Student对象。

例子1:默认串行化的例子(p123)

import .*;

import ;

class Bag implements Serializable{

Color color;

String price;

int size;

String type;

public Bag(Color color,String price,int size,String type){

}

=color;

=price;

=size;

=type;

}

public class DefaultSerial{

public static void main(String args[]) throws IOException,ClassNotFoundException{

Color cObj=;

Bag bagObj=new Bag(cObj,"57",18,"Student bag");

FileOutputStream fileOStream=new FileOutputStream("");

ObjectOutputStream objOStream=new ObjectOutputStream(fileOStream);

try

{

bject(bagObj);

();

}catch(IOException e)

{

}

bagObj=null;

FileInputStream fileInStream=new FileInputStream("");

ObjectInputStream objInStream=new ObjectInputStream(fileInStream);

try

{

bagObj=(Bag)ject();

();

n(e);

}catch(IOException e)

{ n(e);

}

n("******************");

n("There are information about bag:");

n("Color:"+);

n("Price:"+);

n("Size:"+);

n("Type:"+);

}

}

§8.6.3 串行化注意的事项

1.串行化能保存的元素

只能保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量,而且串行化保存的只是变量的值,对于变量的任何修饰符,都不能保存。

2.transient关键字

对于某些类型的对象,其状态是瞬时的,这样的对象是无法保存其状态的,例如一个Thread对象,或一个FileInputStream对象,对于这些字段,我们必须用transient关键字标明

3. 定制串行化

缺省的串行化机制,对象串行化首先写入类数据和类字段的信息,然后按照名称的上升排列顺序写入其数值。如果想自己明确地控制这些数值的写入顺序和写入种类,必须定义自己的读取数据流的方式。就是在类的定义中重写writeObject()和readObject()方法。

例如可在8.6.2的例子中,加入重写的writeObject()和readObject()方法,对Student 类定制其串行化。

private void writeObject(ObjectOutputStream out)throws IOException

{

nt(id);

nt(age);

TF(name);

TF(department);

}

private void readObject(ObjectInputStream in)throws IOException

{

id=t();

age=t();

name=F();

department=F();

}

例子2:定制的串行化(p124)

import .*;

import ;

class Bag implements Serializable{

Color color;

String price;

int size;

String type;

public Bag(Color color,String price,int size,String type){

}

private void writeObject(ObjectOutputStream outObj) throws IOException{

}

private void readObject(ObjectInputStream inObj) throws IOException{

type=F();

price=F();

Object cObj;

try

{

cObj=ject();

color=(Color)(cObj);

TF(type);

TF(price);

bject(color);

nt(size);

=color;

=price;

=size;

=type;

}catch(ClassNotFoundException e){}

}

}

size=t();

public class CustomSerial{

public static void main(String args[]) throws IOException,ClassNotFoundException{

Color cObj=;

Bag bagObj=new Bag(cObj,"57",18,"Student bag");

FileOutputStream fileOStream=new FileOutputStream("");

ObjectOutputStream objOStream=new ObjectOutputStream(fileOStream);

try

{

bject(bagObj);

();

}catch(IOException e)

{

}

bagObj=null;

FileInputStream fileInStream=new FileInputStream("");

n(e);

ObjectInputStream objInStream=new ObjectInputStream(fileInStream);

try

{

bagObj=(Bag)ject();

();

}catch(IOException e)

{ n(e);

}

n("******************");

n("There are information about bag:");

n("Color:"+);

n("Price:"+);

n("Size:"+);

n("Type:"+);

}

}

【本讲小结】

Java中的输入/输出处理是通过使用流技术,用统一的接口表示而实现的。输入/输出流中,最常见的是对文件的处理。Java语言中提供专门处理文件和目录的类,例如:,putStream,tputStream,AccessFile和接口meFilter。输入/输出流根据处理的内容,分为字符流和字节流两种,其中字节流是以byte为基本处理单位的流;而字符流是以16位的Unicode码为处理单位的流。


本文标签: 文件 对象 输出 输入 字节