Java输入输出(I/O)

Download Report

Transcript Java输入输出(I/O)

Java程序设计
Java Programming
Spring, 2013
Java I/O
1.
2.
3.
4.
5.
6.
7.
8.
java.io
File Class
RandomAccessFile Class
InputStream & OutputStream
Reader & Writer
FileInputStream & FileOutputStream
FileReader & FileWriter
BufferedStream
2 /84
I/O



输入(Input)/输出(Output)系统,简称为I/O系统,
对于输入/输出问题,Java将之抽象化为流
(Stream)对象来解决,对不同的输入/输出问题,
提供了相应的流对象解决的方案。
流式输入输出的特点是数据的获取和发送沿数据
序列的顺序进行,即每一个数据都必须等待排在
它前面的数据,等前面的数据读入或送出之后才
能被读写。
3 /84
java.io 包


java.io包中定义与输入、输出流相关的类和接口,
构成了Java语言的I/O框架。
java.io包中定义的各种各样的输入输出流类,它
们都是Object类的直接或间接子类,每一个流类
代表一种特定的输入或输出流。
import java.io.*;
4 /84
流的类结构
• java.io包的类层次结构:
– 以四个顶层抽象类为基础,衍生出系列具体的类
来完成各种输入/输出。
1. InputStream,OutputStream:用于字节的读/写。
2.
3.
Reader,Writer:用于文本(字符)的读/写。
实际使用的是它们的子类的对象。
Object
InputStream
Reader
OutputStream
File
Writer
RandomAccessFile
5/84
File handling
1.
File类
2.
RandomAccessFile类
File类


Fundamental class: File
Represents either a file(文件) or a dir(文件夹)
location in a file system.


Through its pathname(路径名)
A pathname


Unix: /usr/java/bin/javac
Windows: c:\java\bin\javac
7 /84
Java文件路径的表示:
1.
2.

Java约定是用UNIX和URL风格的斜线(/)来作路
径分隔符;
如果用Windows/DOS所使用的反斜线( \ )的约定,
则需要在字符串内使用它的转义序列( \\ )。
例:
 c:\\java\\bin\\javac
(Windows/DOS)
 c:/java/bin/javac
(UNIX和URL风格)
8 /84
Example—separator(分隔符)
//显示分隔符
import java.io.*;
public class Prova {
public static void main(String[] arg) {
System.out.println(File.separator+" - "+
File.separatorChar+" - "+
File.pathSeparator+" - "+
File.pathSeparatorChar);
}
}
• Output (in Windows)
\-\-;-;
• Output (in Unix):
/-/-:-:
File类
java.io包中的File类提供了获得文件基本信息及文
件操作的方法。
通过File类,可以建立与磁盘文件的联系;可以用
来获取或设置文件或目录的属性,但不支持从文件
里读取数据或者往文件里写数据。
构造方法



1.
2.
3.
File(String filename);
File(String directoryPath, String filename);
File(File f, String filename);
10 /84
Example:

创建文件和文件夹
//创建文件夹
File file1 = new File("e:/java");
file1.mkdir();
//在目录中创建文件
File file2 = new File(file1,"test.txt");
file2.createNewFile();
File类的常用方法

操作文件属性的方法





public boolean canRead();判断文件是否是可读的。
public boolean canWrite();判断文件是否可被写入。
public boolean exists(); 判断文件是否存在。
public boolean isFile(); 判断文件是否是一个正常文
件,而不是目录。
public boolean isDirectroy();判断文件是否是一个目
录。
12 /84
File类的常用方法

获取文件的名称、路径




public String getName():获取文件的名字。
public String getPath():得到文件的路径名。
public String getAbsolutePath():得到文件的绝对
路径名。
public String getParent():得到文件的上一级目录
名。
13 /84
File类的常用方法

获取文件处理信息



public long length(): 获取文件的长度(单位是字节)。
public long lastModified():获取文件最后修改时间。
public boolean delete():删除文件。
14 /84
File类的常用方法

目录(directory)操作



创建一个名为File的目录:
 public boolean mkdir()
列出目录中的文件
 public String[] list()
 public File[] listFiles()
在目录中创建文件
 public boolean createNewFile()
15 /84
Example:
//创建文件夹
File file1 = new File(“e:/java”); //创建File对象
file1.mkdir();
//通过File对象创建文件夹
//在目录中创建文件
File file2 = new File(file1,"test.txt");
file2.createNewFile();
//通过File对象创建文件
//显示文件夹中所有文件的文件名
String[ ] files = file1.list();
for(int i = 0; i<files.length; i++)
System.out.print(files[i]);
//显示文件夹中所有文件的对象
File[ ] files = file1.listFiles();
for(int i = 0; i<files.length; i++)
System.out.println(files[i].getName()+"\t"+ files[i].length());
17/84
Example 1 to test the methods of ‘File’
import java.io.File;
public class TryFile {
public static void main(String[] args) {
// Create an object that is a directory
File myDir = new File(“C:/jdk1.5.0/src/java/io”);
System.out.println(myDir + (myDir.isDirectory() ? “ is” : “ is not”) + “ a directory.”);
// Create an object that is a file
File myFile = new File(myDir, “File.java”);
System.out.println(myFile + (myFile.exists() ? “ does” : “ does not”) + “ exist”);
System.out.println(myFile + (myFile.isFile() ? “ is” : “ is not”) + “ a file.”);
System.out.println(myFile + (myFile.isHidden() ? “ is” : “ is not”) + “ hidden”);
System.out.println(“You can” + (myFile.canRead() ? “ “ : “not “) + “read “ + myFile);
System.out.println(“You can” + (myFile.canWrite() ? “ “ : “not “) + “write “ + myFile);
}
}
18/84
文件的随机访问类
(RandomAccessFile)




RandomAccessFile类可以对文件进行随机读写操
作。
用来访问保存数据记录的文件;
数据记录是指对应于数据源中一行信息的一组完
整的相关信息。
例如:
时间
地点
课程
2013/04/02 1302教室 Java程序设计
班级
数媒2011
19 /84
文件的随机访问类
(RandomAccessFile)


定义了对各种数据类型进行读写的方法,如:
byte, char, double, float, int, short, long等。
可以用getFilePointer()方法获得当前的文件读取
指针,可以用seek(long pos)方法访问记录,并
进行读写。


getFilePointer():返回文件指针在文件中的当前偏移
量。
seek(long pos): 设置从文件开头到文件指针的偏移
量为pos,在偏移量pos的位置发生下一个读取或写入
操作。
文件的随机访问类(RandomAccessFile)
 创建一个RandomAccessFile对象
1. RandomAccessFile(File file, String mode)
2. RandomAccessFile(String name, String mode);
• 构造函数可能产生FileNotFoundException及IOException异常
• mode
1. r:只读;
2. rw:可读可写
File file=new File(“d:\\lx\\a.txt”);
RandomAccessFile rf=new RandomAccessFile( file, ”rw”) ;
RandomAccessFile rfile=new RandomAccessFile(“d:\\lx\\a.txt”, ”rw”);
21/84
文件的随机访问类(RandomAccessFile)

1.
2.
3.
读写数据的常用方法
读、写基本数据类型: readInt()、writeInt(int n)等;
读取文件中的一行: readLine();
读、写UTF字符串: readUTF()、writeUTF(String str);

UTF-8:8-bit Unicode Transformation Format,一种针
对Unicode的可变长度字符编码 。
22/84
文件的随机访问类
(RandomAccessFile)

文件随机读写流的读取指针控制




long getFilePointer();
 得到当前的文件读取指针。
void seek(long pos);
 把指针从开始移动到pos位置。
long length();
 得到文件的长度(有多少个字节) 。
void setLength(long newLength);
 重新设置文件的长度。
What is the stream (流) ?


流是数据的有序序列。
流可分为输入流和输出流(按流动方向) :


输入流指从某个数据来源输入Java应用程序的数据序列,
InputStream和Reader处理输入
输出流指Java应用程序向某个数据目的地输出的数据序
列, OutputStream和Writer处理输出
24 /84
输入流、输出流

输入流、输出流分别如下图所示。
输入流
数据源
程序
输入流示意图
输出流
程序
数据宿
输出流示意图
25 /84
System类和标准输入输出流




System类代表系统,系统级的很多属性和控制方
法都放置在该类的内部。System类在java.lang
包中。
You do not instantiate the System class to use it.
All of System's variables and methods are
static variables and static cmethods.
To use a class variable, you use it directly from
the name of the class using Java's dot (.)
notation.
26 /84
标准流-- System Class
//获得运行程序的电脑系统的用户名
class UserNameTest {
public static void main(String[] args) {
String name;
name = System.getProperty("user.name");
System.out.println(“Your name is “ + name);
}
}
• Notice that the program never instantiates a System
object. It just references the getProperty method and
the out variable directly from the class.
27 /84
标准流

System类的3个静态变量就是系统的三个标准流:
1.
System.in:表示系统的标准输入流对象,通常的
环境下标准输入流指向键盘输入;
System.out:表示系统的标准输出流对象,通常
环境下指向屏幕输出;
System.err:表示系统的标准错误输出流对象,通
常环境下也指向屏幕输出。
2.
3.


上述三个标准流由系统负责打开关闭,使用时不
需要显式地打开或关闭。
System.out和System.err都用于输出,通常情况下:

Syetem.out用于程序输出一般信息,而System.err用于输出错误信
息和其他需要引起用户立即注意的信息。

在系统中,System.out具有缓冲机制,而System.err是没有缓冲的,
28 /84
这是两者之间的一个重要区别。
The Standard I/O Streams


Standard Input Stream

System.in -- The System class provides a stream for reading

text -- the standard input stream.
Use System.in.read to read the input entered by user.
Standard Output and Error Streams

System.out -- The standard output stream is typically used for
command output.

System.err -- The standard error stream is typically used to
display any errors that occur when a program is running.

The print, println, and write Methods

The print and println methods write their
String argument to the screen.
System.out.println("Duke is not a penguin!");

The write method is used to write bytes to the
stream.
29 /84
//DataTypePrintTest.java, println方法的重载
public class DataTypePrintTest {
public static void main(String[] args) {
String stringData = "Java Mania";
char[ ] charArrayData = { 'a', 'b', 'c' };
int integerData = 4;
long longData = Long.MIN_VALUE;
float floatData = Float.MAX_VALUE;
double doubleData = Math.PI;
boolean booleanData = true;
System.out.println(stringData);
System.out.println(charArrayData);
System.out.println(integerData);
System.out.println(longData);
System.out.println(floatData);
System.out.println(doubleData);
System.out.println(booleanData);
System.out.println();
}
}
30
//标准输入、输出
import java.io.*;
class TranslateByte{
public static void main(String[] args) throws IOException{
byte from=(byte)args[0].charAt(0);
byte to=(byte)args[1].charAt(0);
int b;
while((b=System.in.read())!=-1)
//从键盘读入一个byte
System.out.write(b==from ? to : b);//输出到屏幕
}
}
javac TranslateByte.java
java TranslateByte b B
输入:
abracadabra!
输出:
Args[0]
Args[1]
aBracadaBra!
31
32 /84
标准输入输出示例:
import java.io.*;
public class StandardIO1{
public static void main(String []args) {
int ch;
System.out.println("请输入一行字符");
try{
//read in a byte from keybord
while((ch=System.in.read())!='\r')
System.out.write(ch);
//写入标准输出流
}catch(IOException e){
System.out.println(e.toString());
}
}
}
System.out.write('\n');
33 /84
34
流的分类

字节流和字符流



InputStream和OutputStream处理8位字节流数据
Reader和Writer处理16位的字符流数据
节点流和处理流(按流的处理位置 )


节点流:可以从或向一个特定的地方(节点)读写数据。
如FileReader 。
处理流:使用节点流作为输入或输出。 处理流不直接与
数据源或目标相连,而是与另外的流进行配合,对数据
进行某种处理,例如:
 BufferedReader,
 InputStreamReader等。
35 /84
字符流和字节流
java.io包中类和接口从功能上主要分为字符流类
型和字节流类型

1.
2.
字符(character)流是指数据序列的基本构成单位是16
位的Unicode字符数据,如:各类基于字符编码的纯文
本文件。
字节(byte)流是指数据序列的基本构成单位是8位的字
节数据,如:各类基于二进制数据的文件、图形图像
文件。
36 /84
文本文件(Text Files,纯字符文件)
vs. 二进制文件(Binary Files)

Text file:



纯文本文件是指的只包含纯文字和字符的文件,这些文
字是没有格式的。
Example:
 ASCII (binary)文件: 00110001, 00110010, 00110111
 记事本文件(.txt文件,默认ANSI编码 )。
Binary file:


非字符文件,如:图片、声音、word文档。
文件含有特殊的格式及计算机代码 。
37 /84
字节流(Byte Streams)

字节流可分为输入字节流和输出字节流


抽象类 InputStream 用于表示所有输入字节流
抽象类 OutputStream 用于表示所有输出字节流
38 /84
Byte Stream family
System.in
System.out
System.err
39 /84
InputStream和OuputStream两个抽象类的子类
40
InputStream类







该抽象类作为所有输入字节流类的基类,声明用于读取字节
流数据的通用方法。
public abstract int read() throws IOException;
public int read(byte[] buf, int offset, int count)
throws IOException;
public int read(byte[] buf) throws IOException;
public long skip(long count) throws IOException;
public int available() throws IOException;
public void close() throws IOException;


Every method here can throw an IOException;
If a programmer uses any of these methods, he/she
must catch IOException (or Exception);
41 /84
How to do I/O
import java.io.*;

1.
2.
所有的流类对象在使用前必须打开(即:创建),
在使用后必须关闭。
Open the stream:创建流对象
Use the stream (read, write, or both)

3.
通过流对象调用方法
Close the stream:

关闭流,释放I/O资源
42 /84
InputStream类



创建InputStream类对象时,便自动打开了对象所表示的
输入流;
InputStream所有与输入相关的方法声明抛出异常类
IOException
InputStream类的对象在完成数据输入后,除标准输入流
类对象System.in外,必须调用close方法关闭输入流,通
常可将该方法的调用放入finally语句块中
43
import java.io.*;
Example:
public class StandardIO1{
public static void main(String []args) throws IOException {
int b;
InputStream stdin1= System.in; //声明输入字节流并指向标准输入流
try {
b = stdin1.read( );
//使用流,从键盘读入一个字节
System.out.println((char)b);
System.out.println(b);
stdin1.close();
//关闭流
}catch(IOException ie) {
Output:
System.out.println();
}
a
}
}
a
97
/***** HelloWorld.java *****/
import java.io.*;
public class HelloWorld {
public static void main( String[ ] args ) {
byte[] ba = new byte[10];
InputStream stdin = System.in;
System.out.println("Please input a string: ");
try{
stdin.read(ba);
//从键盘读入多个字节
}catch(IOException ie){
System.out.println();
}finally {
}
}
}
String s = new String(ba);
System.out.println("The string read in is "+ s);
45/84
OutputStream类



当创建OnputStream类对象时,便自动打开了对
象所表示的输出流。
OutputStream所有与输出相关的方法声明抛出
异常类IOException
OutputStream类的对象在完成数据输出后,除
标准输出流对象System.out外,必须调用close
方法关闭输出流
46 /84
OutputStream类






该抽象类作为所有输出字节流类的基类,声明用于输出字
节流数据的通用方法:
void write(int b) throws IOException
public void write(byte[] buf, int offset, int count)
throws IOException
void write(byte[] b) throws IOException
void flush() throws IOException
void close() throws IOException
47 /84
OutputStream类
public abstract void write(int b)
throws IOException



将指定的字节写入此输出流。
write 的常规协定是:向输出流写入一个字节。要写入的字
节是参数 b 的八个低位。b 的 24 个高位将被忽略。
OutputStream 的子类必须提供此方法的实现。
OutputStream stdout = System.out;
stdout.write(104);
// ASCII ‘h’ ,一个字节
stdout.flush();
字符流(Character Streams)

字符流可分为输入字符流和输出字符流


抽象类 Reader 用于表示所有输入字符流
抽象类 Writer 用于表示所有输出字符流
49 /84
Character Stream Family
50 /84
Reader和Writer的主要子类如下:
51 /84
Reader类
• 该抽象类作为所有输入字符流类的基类,声明用于读
取输入字符文本数据的通用方法:






public int read();
public abstract int read(char[] buf, int
offset,int count);
public int read(char[] buf);
public long skip(long count);
public int available();
public abstract void close();
52 /84
Writer类

该抽象类作为所有输出字符流类的基类,声明用于输出字符
文本数据的通用方法:










public void write(int ch);
public abstract void write(char[] buf, int offset, int count);
public void write(char[] buf);
public void write(String str, int offset, int count);
public void write(String str);
public Writer append(char c)
public Writer append(CharSequence csq)
public Writer append(CharSequence csq, int start, int end)
public abstract void flush();
public abstract void close();
53 /84
文件的读写



FileOutputStream/FileInputStream 是抽象类
InputStream/OutputStream的子类.
它们生成与文件链接的字节流。
为打开文件,只需创建
FileOutputStream/FileInputStream类的一个对
象,在构造函数中以参数形式指定文件的名称。
54 /84
文件的读写




FileInputStream类和FileOutputStream类的构
造函数是创建一个输入输出的对象,通过引用该
对象的读写方法,来完成对文件的输入输出操作。
在构造函数中,需要指定与所创建的输入输出对
象相连接的文件。
要构造一个FileInputStream对象,所连接的文件
必须存在而且是可读的;
构造一个FileOutputStream对象,如果输出文件
已经存在且可写,该文件内容会被新的输出所覆
盖。
55 /84
FileInputStream类


从InputStream中派生出来,其所有方法都从InputStream类继承
而来。基本操作步骤:
1>建立文件的输入流对象
2>从输入流中读取字节
3>关闭流
常用构造方法




public FileInputStream(String name) throws FileNotFoundException
public FileInputStream(File file) throws FileNotFoundException
均会抛出FileNotFoundException异常
构造方法参数指定的文件称作输入流的源
FileInputStream fin = new FileInputStream(“c:\\java\\test.java”);
56 /84
FileInputStream
文件字节流的读取



read方法给程序提供从输入流中读取数据的基本方法。
read方法按顺序读取流,直到流的末尾或流被关闭(close()
方法)。
read方法的格式:
 public int read() throws IOException
 从输入流中顺序读取单个字节的数据,并将所读单个
字节以int返回。如果已到达文件末尾,则返回 -1 。


public int read(byte b[]) throws IOException
public int read(byte b[], int off, int len)
throws IOException
 把多个字节读到一个字节数组中,返回实际所读的字节
数。
57 /84
Example with FileInputStream
/* class example FileIn.java */
import java.io.*;
public class FileIn{
public static void main(String[] args){
try {
FileInputStream fin =
new FileInputStream(“c:\\java\\test.java”);
int input;
while ((input = fin.read()) != -1)//读取字节直到末尾
System.out.print((char)input);
fin.close();
}catch(IOException ie){
System.out.println(e);
}
}
}
58/84
FileOutputStream类



从OutputStream中派生出来,其所有方法都从OutputStream
类继承来的。
基本操作步骤: 1>建立文件的输出流对象
2>向输出流中写字节
3>关闭流
常用构造方法
 public FileOutputStream(String name)
 public FileOutputStream(File file)
 如果输出流要写入数据的文件已经存在,该文件中的数据
内容就会被刷新;如果要写入数据的文件不存在,该文件
就会被建立。
FileOutputStream fout = new FileOutputStream(“c:\\java\\test.java”);
59 /84
FileOutputStream文件输出字节流


write方法把字节发送给输出流,顺序地写文件,直
到流的末尾或流被关闭(close()方法)
write方法的格式:


public void write(byte b[]) throws IOException
public void write(byte b[], int off, int len)
throws IOException
60 /84
/*例:编写程序,接收用户从键盘输入的数据,回车后保存到
文件test.txt中。若用户输入符号#,则退出程序。*/
import java.io.*;
public class WriteFile{
public static void main(String args[]) {
byte buffer[]=new byte[128];
System.out.println("请输入数据,回车后保存到文件test.txt");
System.out.println("输入 # 则退出!");
try{
FileOutputStream f=new FileOutputStream("test.txt");
while(true){
int n=System.in.read(buffer);//从键盘读多个字节存入buffer
if(buffer[0]=='#' )
break;
f.write(buffer, 0, n);
f.write(‘\n');
}
f.close();
}catch(IOException e){
System.out.println(e.toString());
}
}
}
61/84
上例程序运行结果如图所示:
62/84
例:使用FileInputStream类与FileOutputStream类复制文件。
/* class example FileIn_Out.java */
/* assumes each char is a single byte */
import java.io.*;
public class FileIn_Out{
public static void main(String[] args) {
try {
FileInputStream fin=new FileInputStream(“c:\\java\\file1.java”);
FileOutputStream fout=new FileOutputStream(“c:\\java\\file2.java”);
byte b[]= new byte[512];
while((fin.read(b, 0, 512))!=-1)
fout.write(b);
fin.close();
fout.close();
}catch(IOException ie) {
System.out.println(ie);
}catch(Exception e) {
System.out.println(e);
}
}
63/84
}
//File and File Stream -- FileStream.java
import java.io.*;
class filestream {
public static void main(String args[]) {
try{
File inFile=new File(“file1.txt");
File outFile=new File(“file2.txt");
FileInputStream fis=new FileInputStream(inFile);
FileOutputStream fos=new FileOutputStream(outFile);
int c;
while((c=fis.read())!=-1)
fos.write(c);
fis.close(); fos.close();
}catch(FileNotFoundException e) {
System.out.println("FileStreamsTest: "+e);
}catch(IOException e) {
System.err.println("FileStreamsTest: "+e);
}
}
}
7.3 File I/O
64/84
FileReader类



从InputStreamReader中派生出来,其所有方法都从
InputStreamReader类和Reader类继承而来。
基本操作步骤: 1>建立文件的输出流对象
2>向输出流中写字符
3>关闭字符流
常用构造方法

public FileReader(String name) throws FileNotFoundException

public FileReader (File file) throws FileNotFoundException


均会抛出FileNotFoundException异常
构造方法参数指定的文件称作输入流的源.
65 /84
FileReader类:文件字符流的读取


read方法给程序提供从输入流中读取数据的基本
方法。
read方法的格式:

public int read() throws IOException



从源中顺序读取一个字符,以int返回。
public int read(char ch[]) throws IOException
public int read(char ch[], int off, int len)
throws IOException

把多个字符读到一个字符数组中,返回实际所读
的字符数。
66 /84
//FileIn.java
import java.io.*;
class FileIn {
public static void main(String args[]) throws IOException{
int i;
FileReader fr;
try {
fr = new FileReader("D:\\workspace\\test\\FileIn.java");
while((i = fr.read())!= -1)
System.out.print((char) i);
fr.close();
}catch(FileNotFoundException e) {
System.out.println("File Not Found");
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Usage: ShowFile File");
}
}
}
67/84
//FileReaderSample.java
import java.io.*;
public class FileReaderSample {
public static void main(String args[ ]) throws IOException{
char data[ ]=new char[100]; //建立可容纳100个字符的数组
// 建立对象fr
FileReader fr=new FileReader("D:\\workspace\\copy.txt");
// 将数据读入字符数组data内
int num=fr.read(data);
// 输出在控制台
System.out.println("Characters read= "+num);
for(int i=0; i<data.length; i++){
System.out.println("data["+i+"]="+data[i]);
}
fr.close();
}
}
68/84
FileWriter类



从OutputStreamReader中派生出来,其所有方法
都从OutputStreamReader类和Writer类继承而来。
基本操作步骤: 1>建立文件的输出流对象
2>向输出流中写字符
3>关闭字符流
常用构造方法



public FileWriter(String name)
public FileWriter(File file)
均会抛出FileNotFoundException异常
69 /84
FileWriter类:文件字符流的输出


write方法给程序提供把字符数据写入到输出流的基
本方法。
write方法的格式




public void write(char b[ ]) throws IOException
public int write(char b[ ], int offset, int len) throws
IOException
public int write(String str) throws IOException
public int write(String str, int offset, int len) throws
IOException
70 /84
BufferedStream(缓冲流)
处理流
节点流
71 /84
BufferedStream缓冲流
• BufferedReader和BufferedWriter类被用来从基
于字符的输入和输出流中读取和写入文本。
• BufferdReader类缓存字符以更高效的读取字符串,数
组和文本行。
• BufferedWriter类缓存字符以更高效的写入字符串,数
组和文本行
Add BufferedStream to improve performance
72 /84
BufferedStream缓冲流
• 增加缓冲区流,减少访问硬盘的次数,提高效率。
处理
文件
文件流
file1.txt
输入流
输入缓
冲区
缓冲区流
程序
输出
file2.txt
缓冲 输出流
区
73
缓冲流--BufferedReader类
• Reader类的直接子类
 构造方法

public BufferedReader(Reader in, int sz);



任何Reader流都可
以用来包装成缓冲流
//sz为缓冲区的大小
public BufferedReader(Reader in);
BufferedReader对象的创建

先创建一个Reader子类的对象,然后使用这个对象来创建
缓冲流对象。
FileReader inOne = new FileReader("Student.txt");
BufferedReader inTwo = new BufferedReader(inOne);
74 /84
缓冲流--BufferedReader类

缓冲流的读取

从缓冲
区读取
public int read() throws IOException
读取一个字符

public int readLine() throws IOException
读取一行文本

读取完毕后,最好调用close()方法关闭流。
75 /92
BufferedWriter类


Writer类的直接子类
构造方法



public BufferedWriter(Writer in,int sz)
public BufferedWriter(Reader in)
BufferedWriter对象的创建

先创建一个Writer子类的对象,然后使用这个对象来创
建缓冲流对象。
FileWriter outOne = new FileWriter("Student.txt");
BufferedWriter outTwo = new BufferedWriter(outOne);
76 /84
BufferedWriter类

缓冲流的写入


public void write(String str) throws IOException
 向缓冲区写入一个字符串。
public int writeLine(String str,int off,int len) throws IOException


向缓冲区写入一个字符串的一部分。
输出完毕后,最好调用close()方法关闭流。
77 /84
/**ReadWriteFile.java--读出1.txt中的内容,写入2.txt中 */
import java.io.*;
public class ReadWriteFile{
public static void main(String[] args){
try{
File read = new File(“c:\\1.txt”);
File write = new File(“c:\\2.txt”);
BufferedReader br = new BufferedReader(new FileReader(read));
BufferedWriter bw = new BufferedWriter(new FileWriter(write));
String temp = null;
temp = br.readLine();
//读一行文本
while(temp != null){
bw.write(temp + “\r\n”);
//写文件, “\r\n”-回车只适用Windows系统
temp = br.readLine();
//继续读文件
}
bw.close();
br.close();
}catch(FileNotFoundException e){ //文件未找到异常
System.out.println (e);
}catch(IOException e){
\r\n是windows下的换行
System.out.println (e);
}
}
}
\n是UNIX下的
78/84
//BufferedStream.java
import java.io.*;
public class BufferedStream {
public static void main(String[] args){
try{
BufferedWriter out=new BufferedWriter(new FileWriter("D:\\test.txt"));
out.write("Hello,World");
out.close();
BufferedReader in=new BufferedReader(new FileReader("D:\\test.txt"));
String s;
s = in.readLine();
System.out.println(s);
in.close();
}catch(Exception e){
System.out.println("error");
}
}
}
79/84
对象串行化(Serialization)





对象(object)的寿命通常随着生成该对象的程序的终止而
终止。某些时候,需要将对象的状态保存下来,将来需
要的时候可以恢复。
对象的这种能记录自己的状态以便将来再生的能力,叫
做对象的 持续性(persistence)。
对象通过写出描述自己状态的数值来记录自己的过程,
叫做对象的串行化(Serialization)。
串行化的主要任务是写出对象实例变量的数值。如果实
例变量是另一对象的一引用,则引用的对象也要串行化
。这个过程是递归的。
对象串行化机制就是将程序中对象的状态转化为一个字
节流,存储在文件中,作为这个对象的一个副本,之后
再从文件中把对象读取出来重新建立。
80 /84
Serializable接口


在java.io包中,接口Serializable用来作为实现对象
串行化的工具,只有实现了Serializable接口的类的
对象才可以被串行化。
Serializable接口中不含有任何的方法声明,是个空
接口。其定义如下:
public interface Serializable{ }
 实现Serializable接口,不需要编写任何的实现代
码。这个接口只是一个特殊的标记,用来表示一
个类可以被串行化。
 如果一个类可以串行化,它的所有子类都可以串
行化。
81 /84
Java标记接口



标识接口是没有任何方法和属性的接口.
它仅仅表明实现它的类属于一个特定的类型,供其
他代码来测试允许做一些事情.
使用标记接口的唯一目的是使得可以用
instanceof进行类型查询,例如:
if(obj instanceof Serializable) {………}
对象串行化(Serialization)




不参与串行化的数据可以用关键字transient(瞬
时的)来修饰。
比如:通常出于安全性的考虑,某些不宜公开的
数据(如用户的密码)用transient来修饰,能够
使其不被串行化。
用static修饰的静态成员变量与类对象无关,串行
化过程也与之无关。
有些对象,如Thread、FileInputStream、
FileOutputStream等对象,其对象状态也是瞬时
的,也不能进行串行化。
83 /84
//Example: Serializable接口
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = 1663183895424656802L;
int id;
String name;
int age;
String department;
public Student(){ }
}
public Student(int id, String name, int age, String department){
this.id = id;
this.name = name;
this.age = age;
this.department = department;
}
84 /84
读写对象流
ObjectInputStream和 ObjectOutputStream

java.io包中,提供了ObjectInputStream (对象输入
流)和ObjectOutputStream(对象输出流),可读、写
对象。

对象串行化(serialization) 通过ObjectOutputStream将
对象状态保存下来(将对象保存到文件中,或者通过网络
传送到其他地方);
反串行化(deserialization) 再通过ObjectInputStream将
对象状态恢复。

85 /84
serialVersionUID


实现Serializable接口,需要定义域:serialVersionUID。
serialVersionUID是为了反序列化的时候JVM比对类的版本。有两种
生成方式:
1.
2.
一个是默认的1L,比如:
private static final long serialVersionUID = 1L;
一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字
段,比如:
private static final long serialVersionUID = xxxxL;

在反序列化的时候,即:将流转换为类的实例的时候,JVM会把传
来的字节流中的serialVersionUID与本地相应实体(类)的
serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列
化,否则就会出现序列化版本不一致的异常。

当一个类实现了Serializable接口,如果没有定义serialVersionUID,
Eclipse会提供这个提示功能告诉你去定义 。在Eclipse中点击类中
warning的图标一下,Eclipse就会自动给定两种生成的方式。如果不
想定义它,在Eclipse的设置中也可以把它关掉的,或者全部默认为
1L.
写对象流


ObjectOutputStream中用writeObject()方法可以
直接将对象保存到输出流中。
writeObject( )用于对象的串行化。


写出了重构一个类对象所需要的信息:对象的类、类的
标记和非transient的对象成员,如果对象包含其他对象
的引用,则这些对象也会被串行化。
串行化能保存的元素

只能保存对象的非静态成员变量,不能保存任何的成员
方法和静态的成员变量,而且串行化保存的只是变量的
值,对于变量的任何修饰符,都不能保存。
87 /84
读对象流


在ObjectInputStream中用readObject()方法可以
直接读取一个对象,
readObject( )方法从字节流中反串行化对象,也
就是将对象恢复过来。


每次调用readObject( )方法都返回流中下一个对象;
对象的字节流并不包含类的字节码,只是包含类名及其
签名,当readObject( )读取对象时,Java虚拟机需要装
载指定的类(恢复的对象的类),如果找不到这个类,则
此方法会抛出ClassNotFoundException异常。
88 /84
反串行化--恢复对象状态
import java.io.*;
public class TestSeria {
public static void main(String[] args){
Student stu=new Student(981036,"Liu Ming",18, "CSD");
try{
FileOutputStream fo=new FileOutputStream("data.ser");
ObjectOutputStream so=new ObjectOutputStream(fo);
so.writeObject(stu);
so.close();
}catch(IOException e){
System.out.println(e);
}
}
}
89 /84
import java.io.*;
public class test {
public static void main(String[] args) throws IOException,ClassNotFoundException {
//串行化
Student s1 = new Student(1,"Mar", 20, "Computer_Science");
Student s3 = new Student(2,"Cathy", 21, "Software_Engineering");
FileOutputStream fos = new FileOutputStream("D:\\serialization\\Student.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s1);
oos.writeObject(s3);
//反串行化
FileInputStream fis = new FileInputStream("D:\\serialization\\Student.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Student s2, s4;
s2 = (Student) ois.readObject(); //必须添加强制类型转换
s4 = (Student) ois.readObject();
System.out.println("Student Information:");
System.out.println(s2.id+“ ”+s2.name+" “+s2.age+" “+s2.department);
System.out.print(s4.id+" “+s4.name+" “+s4.age+" “+s4.department);
oos.close();
ois.close();
}
}
90/84
定制串行化


默认的串行化机制,对象串行化首先写入类数据
和类字段的信息,然后按照名称的上升排列顺序
写入其数值。
如果想自己明确地控制这些数值的写入顺序和写
入种类,必须定义自己的读取数据流的方式。就
是在类的定义中重写writeObject()和
readObject()方法。


例如:在一个可以串行化的类中有一个不可串行化的对
象,但又想保存该对象的状态信息该如何是好?
例:ObjectSerialization.java
91 /84
import java.io.*; //Student类实现Serializable接口
public class Student implements Serializable {
int id;
String name;
int age;
String department;
public Student(int id, String name, int age, String department){
this.id = id;
this.name = name;
this.age = age;
this.department = department;
}
//一般可不重写,定制串行化时需要重写writeObject()方法
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeInt(id);
out.writeInt(age);
out.writeUTF(name);
out.writeUTF(department);
}
//一般可不重写,定制串行化时需要重写readObject()方法
private void readObject(ObjectInputStream in) throws IOException {
id=in.readInt();
age=in.readInt();
name=in.readUTF();
department=in.readUTF();
92
}
}
import java.io.*;
public class ObjectSerialization{
public static void main(String[] args) throws
IOException,ClassNotFoundException{
Student st=new Student(20010901,"黎明",20,"计算机系"); //创建可串行化的st对象
FileOutputStream fout=new FileOutputStream("data.txt");
ObjectOutputStream sout=new ObjectOutputStream(fout);
try{ //输出流将对象状态存入文件"data.txt”
sout.writeObject(st);
sout.close();
}catch(IOException e){}
st=null;
// st对象与ObjectInputStream联系起来
FileInputStream fin=new FileInputStream("data.txt");
ObjectInputStream sin=new ObjectInputStream(fin);
try{
//输入流将对象状态从文件"data.ser"读出
st=(Student) sin.readObject();
sin.close();
}catch(IOException e){}
}
}
System.out.println("学生信息:"); //输出验证
System.out.print("学号: " + st.id +"; 姓名: " + st.name+"; 年龄: " + st.age);
System.out.println("; 院系: " + st.department);
93
定制串行化:(参考)
调用重写的writeObject()和readObject()方法



方法writeObject()处理对象的序列化。
如果在Student 类里面重写该方法,它将会被
ObjectOutputStream调用而不是默认的序列化进程。
如果你是第一次看见它,你会很惊奇尽管它们被外部类调
用但事实上这是两个private的方法。并且它们既不存在于
java.lang.Object,也没有在Serializable中声明。那么
ObjectOutputStream如何使用它们的呢?因为
ObjectOutputStream使用了反射来寻找是否声明了这两个
方法。因为ObjectOutputStream使用getPrivateMethod,
所以这些方法不得不被声明为priate以至于供
ObjectOutputStream来使用。
94 /84