java I/O整体框架
java I/O整体框架:
Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的:
?
其中FilterInputStream ,FilterOutputStream,FilterReader,FillerWriter为Decorator类,用来包装.
OutpurtStraeamReader,InputStreamWriter是用来转换字节流到字符流.
RandomAccessFile并不是从InputStream或OutputStream继承过来.它只实现DataIput和DataOutput方法.
接口DataInput 中定义的方法主要包括从流中读取基本类型的数据、读取一行数据、或者读取指定长度的字节数。如:readBoolean( )、adInt( )、readLine( )、readFully( ) 等。
接口DataOutput 中定义的方法主要是向流中写入基本类型的数据、或者写入一定长度的字节数组。如:writeChar( )、writeDouble( )、write( ) 等。 下面详细介绍RandomAccessFile类中的方法。
◇ 构造方法:
RandomAccessFile(String name,String mode); //name是文件名,mode
//是打开方式,例如"r"表示只读,"rw"表示可读写,"
RandomAccessFile(File file,String mode); //file是文件对象
◇ 文件指针的操作
long getFilePointer( ); //用于得到当前的文件指针
void seek( long pos ); //用于移动文件指针到指定的位置
int skipBytes( int n ); //使文件指针向前移动指定的n个字节
接口DataInput 中定义的方法主要包括从流中读取基本类型的数据、读取一行数据、或者读取指定长度的字节数。如:readBoolean( )、readInt( )、readLine( )、readFully( ) 等。
例子:
import java.io.*;
?
?
public class IOStreamDemo {
??????public void samples() throws IOException {
???????????//1. 这是从键盘读入一行数据,返回的是一个字符串
???????????BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in));
???????????System.out.print("Enter a line:");
???????????System.out.println(stdin.readLine());
???????????//2. 这是从文件中逐行读入数据
???????????BufferedReader in = new BufferedReader(new FileReader("IOStreamDemo.java"));
???????????String s, s2 = new String();
???????????while((s = in.readLine())!= null)
??????????????????????s2 += s + "\n";
???????????in.close();
???????????//3. 这是从一个字符串中逐个读入字节
???????????StringReader in1 = new StringReader(s2);
???????????int c;
???????????while((c = in1.read()) != -1)
??????????????????????System.out.print((char)c);
???????????//4. 这是将一个字符串写入文件
???????????try {
??????????????????????BufferedReader in2 = new BufferedReader(new StringReader(s2));
??????????????????????PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
??????????????????????int lineCount = 1;
??????????????????????while((s = in2.readLine()) != null )
?????????????????????????????????out1.println(lineCount++ + ": " + s);
??????????????????????out1.close();
???????????} catch(EOFException e) {
??????????????????????System.err.println("End of stream");
???????????}
??????}
}
?
?
Java提供了这样一个功能,将标准的输入输出流转向,也就是说,我们可以将某个其他的流设为标准输入或输出流,看下面这个例子:
?
?
import java.io.*;
public class Redirecting {
???????public static void main(String[] args) throws IOException {
??????????????PrintStream console = System.out;
??????????????BufferedInputStream in = new BufferedInputStream( new FileInputStream( "Redirecting.java"));
??????????????PrintStream out = new PrintStream( new BufferedOutputStream( new FileOutputStream("test.out")));
??????????????System.setIn(in);
??????????????System.setOut(out);
??????????????BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
??????????????String s;
??????????????while((s = br.readLine()) != null)
?????????????????????System.out.println(s);
??????????????out.close();
??????????????System.setOut(console);
??????}
}
?
在这里java.lang.System的静态方法
?
static void setIn(InputStream in)?
static void setOut(PrintStream out)
?
提供了重新定义标准输入输出流的方法,这样做是很方便的,比如一个程序的结果有很多,有时候甚至要翻页显示,这样不便于观看结果,这是你就可以将标准输出流定义为一个文件流,程序运行完之后打开相应的文件观看结果,就直观了许多。
Java流有着另一个重要的用途,那就是利用对象流对对象进行序列化。下面将开始介绍这方面的问题。
在一个程序运行的时候,其中的变量数据是保存在内存中的,一旦程序结束这些数据将不会被保存,一种解决的办法是将数据写入文件,而Java中提供了一种机制,它可以将程序中的对象写入文件,之后再从文件中把对象读出来重新建立。这就是所谓的对象序列化Java中引入它主要是为了RMI(Remote Method Invocation)和Java Bean所用,不过在平时应用中,它也是很有用的一种技术。
所有需要实现对象序列化的对象必须首先实现Serializable接口。下面看一个例子:
?
?
import java.io.*;
import java.util.*;
public class Logon implements Serializable {
???????private Date date = new Date();
???????private String username;
???????private transient String password;
???????Logon(String name, String pwd) {
??????????????username = name;
??????????????password = pwd;
???????}
???????public String toString() {
??????????????String pwd = (password == null) ? "(n/a)" : password;
??????????????return "logon info: \n " + "username: " + username + "\n date: " + date + "\n password: " + pwd;
???????}
???????public static void main(String[] args) throws IOException, ClassNotFoundException {
??????????????Logon a = new Logon("Morgan", "morgan83");
??????????????System.out.println( "logon a = " + a);
??????????????ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("Logon.out"));
??????????????o.writeObject(a);
??????????????o.close();
??????????????int seconds = 5;
??????????????long t = System.currentTimeMillis()?+ seconds * 1000;
??????????????while(System.currentTimeMillis() < t) ;
??????????????ObjectInputStream in = new ObjectInputStream( new FileInputStream("Logon.out"));
??????????????System.out.println( "Recovering object at " + new Date());
??????????????a = (Logon)in.readObject();
??????????????System.out.println("logon a = " + a);
???????}
}
?
类Logon是一个记录登录信息的类,包括用户名和密码。首先它实现了接口Serializable,这就标志着它可以被序列化。之后再main方法里ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("Logon.out"));新建一个对象输出流包装一个文件流,表示对象序列化的目的地是文件Logon.out。然后用方法writeObject开始写入。想要还原的时候也很简单ObjectInputStream in = new ObjectInputStream( new FileInputStream("Logon.out"));新建一个对象输入流以文件流Logon.out为参数,之后调用readObject方法就可以了。
需要说明一点,对象序列化有一个神奇之处就是,它建立了一张对象网,将当前要序列化的对象中所持有的引用指向的对象都包含起来一起写入到文件,更为奇妙的是,如果你一次序列化了好几个对象,它们中相同的内容将会被共享写入。这的确是一个非常好的机制。它可以用来实现深层拷贝,有关深层拷贝的问题在JavaWorld上有一篇文章做了几种实现方法的介绍和比较,有兴趣者可以去看看。
关键字transient在这里表示当前内容将不被序列化,比如例子中的密码,需要保密,所以没有被写入文件