Ø java.io 包中定义了多个流类型(类或抽象类)来实
现输入/输出功能;可以从不同的角度对其进行分类:
- 按数据流的方向不同可以分为输入流和输出流。(以程序的角度来考虑)
- 按处理数据单位不同可以分为字节流和字符流。
- 按照功能不同可以分为节点流和处理流。
节点流和处理流
Ø 节点流为可以从一个特定的数据源(节点)读写数据(如:文件,内存)
Ø 处理流是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
InputStream
Ø 继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节(8 bit);下图中深色为节点流,浅色为处理流。
InputStream的基本方法
//读取一个字节并以整数的形式返回(0~255),
//如果返回-1已到输入流的末尾。
int read() throws IOException
//读取一系列字节并存储到一个数组buffer,
//返回实际读取的字节数,如果读取前已到输入流的末尾返回-1
int read(byte[] buffer) throws IOException
//读取length个字节
//并存储到一个字节数组buffer,从off位置开始存,最多len
//返回实际读取的字节数,如果读取前以到输入流的末尾返回-1
int read(byte[] buffer, int off, int len)
throws IOException
//关闭流释放内存资源
void close() throws IOException
OutputStream
继承自OutputSteam的流是用于程序中输入数据,且数据的单位为字节(8 bit);下图中深色为节点流,浅色为处理流
OutputStream的基本方法
//向输出流中写入一个字节数据,该字节数据为参数b的低8位
void write(int b) throws IOException
//将一个字节类型的数组中的数据写入输出流
void write(byte[] b) throws IOException
//将一个字节类型的数组中的从指定位置(off)开始的
//len个字节写入到输出流
void write(byte[] b, int off, int len)
throws IOException
//关闭流释放内存资源
void close() throws IOException
//将输出流中缓冲的数据全部写出到目的地
void flush() throws IOException
良好的编程习惯à,先flush(),再close()
Reader
Ø 继承自Reader的流都是用于向程序中输入数据,且数据的单位为字符(16 bit);下图中深色为节点流,浅色的为处理流。
为什么要有字符流(两个字节):比如汉字是两个字节的字符,如果只有字节流,那么每次只能读写半个汉子。
Reader 的基本方法:
//读取一个字符并以整数的形式返回(0~231-1),
//如果返回-1已到输入流的末尾。
int read() throws IOException
//读取一系列字符并存储到一个数组buffer,
//返回实际读取的字符数,如果读取前已到输入流的末尾返回-1
int read(char[] cbuf) throws IOException
//读取length个字符
//并存储到一个数组buffer,从off位置开始存,最多读取len
//返回实际读取的字符数,如果读取前以到输入流的末尾返回-1
int read(char[] cbuf, int off, int len)
throws IOException
//关闭流释放内存资源
void close() throws IOException
Writer
Ø 继承自Writer的流都是用于程序中输入数据,且数据的单位为字符(16 bit);下图中深色为节点流,浅色为处理流。
Writer 的基本方法
//向输出流中写入一个字符数据,该字节数据为参数b的低16位
void write(int c) throws IOException
//将一个字符类型的数组中的数据写入输出流,
void write(char[] cbuf) throws IOException
//将一个字符类型的数组中的从指定位置(offset)开始的
//length个字符写入到输出流
void write(char[] cbuf, int offset, int length)
throws IOException
//将一个字符串中的字符写入到输出流
void write(String string) throws IOException//实际上是调用了String 类型的toCharArry方法。
//将一个字符串从offset开始的length个字符写入到输出流
void write(String string, int offset, int length)
throws IOException
//关闭流释放内存资源
void close() throws IOException
//将输出流中缓冲的数据全部写出到目的地
void flush() throws IOException
节点流类型
类 型 | 字符流 | 字节流 |
File(文件) | FileReader FileWriter | FileInputStream FileOutputStream |
Memory Array | CharArrayReader CharArrayWriter | ByteArrayInputStream ByteArrayOutputStream |
Memory String | StringReader StringWriter | - |
Pipe(管道) | PipedReader PipedWriter | PipedInputStream PipedOutputStream |
|
|
|
EG1:
publicclass TestFileInputStream {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
long num = 0;//用来统计读取的字节数。
int i=0;
// FileInputStream in = null;
FileReader in = null;
String path = "E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\TestFileInputStream.java";
try {
// in = new FileInputStream(path);
in = new FileReader(path);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("找不到指定文件");
System.exit(-1);
}
try {
while((i=in.read())!=-1){
System.out.print((char)i);//将i转换为char类型
num++;
}
in.close();//关闭流
System.out.println("共读取了"+num+"个字节!");
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("文件读取错误!");
System.exit(-1);
}
}
}
Eg2:
publicclass TestFileOutputStream {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
int i = 0;
FileInputStream in = null;
FileOutputStream out = null;
String path = "E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\TestFileInputStream.java";
String path2 = "E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\TestFileInputStream2.java";
try {
in = new FileInputStream(path);
out = new FileOutputStream(path2);
while ((i = in.read()) != -1) {
out.write((char) i);//将从in中读取到的字节写入到out所指定的文件中
}
in.close();
out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("找不到指定文件!");
System.exit(-1);
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("文件复制错误!");
System.exit(-1);
}
System.out.println("文件复制成功!");
}
}
处理流类型:
处理类型 | 字符流 | 字节流 |
Buffering | BufferedReader BufferedWriter | BufferedInputStream BufferedOutputStream |
Filtering | FilterReader FilterWriter | FilterInputStream FilterOutputStream |
Converting between bytes and character | InputStreamReader OutputStreamWriter | 䦋㌌㏒㧀좈琰茞ᓀ㵂Ü |
Object Serialization | - | ObjectInputStream ObjectOutputStream |
Data conversion | - | DataInputStream DataOutputStream |
Counting | LineNumberReader | LineNumberInputStream |
Peeking ahead | PusbackReader | PushbackInputStream |
Printing | PrintWriter | PrintStream |
缓冲流
Ø 缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。
Ø J2SDK提供了四种缓存流,其常用的构造方法为:
BufferedReader(Reader in)
BufferedReader(Reader in,int sz) //sz 为自定义缓存区的大小
BufferedWriter(Writer out)
BufferedWriter(Writer out,int sz)
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,int size)
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out,int size)
l BufferedReader提供了readLine方法用于读取一行字符串(以\r或\n分隔)。
l BufferedWriter提供了newLine用于写入一个行分隔符。
l 对于输出的缓冲流,写出的数据会先在内存中缓存,使用flush方法将会使内存中的数据立刻写出。
Eg:
publicclass TestBufferedInputStream {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
FileInputStream in = null;
BufferedInputStream bis = null;
String path = "E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\TestFileInputStream.java";
try {
in = new FileInputStream(path);
bis = new BufferedInputStream(in);
int c = 0;
System.out.println((char)bis.read());
System.out.println((char)bis.read());
bis.mark(100);//标记,从in的第100个字节开始读。
for(int i=0;i<=10&&(c=bis.read())!=-1;i++){
System.out.print((char)c+" ");
}
System.out.println();
bis.reset();//重新回到标记处。
for(int i=0;i<=10&&(c=bis.read())!=-1;i++){
System.out.print((char)c+" ");
}
bis.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Eg2:
publicclass TestBufferedWriter {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
try {
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\dat.text"));
BufferedReader br=new BufferedReader(new FileReader("E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\dat.text"));
String s;
for(int i=0;i<=100;i++){
s=String.valueOf(Math.random());//产生0-1之间的100个随即数。
bw.write(s);//将随即数写入到文件中。
bw.newLine();//每写入一个数就会换一行。
}
bw.flush();//清空缓存。
while((s=br.readLine())!=null){
System.out.println(s);
}
bw.close();
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
转换流
l InputStreamReader和OutputStreamWriter用与字节数据到字符数据之间的转换。
l InputStreamReader 需要和 InputStream “套接” 。
l OutpStreamWriter 需要和 OutputStream “套接” 。
l 转换流在构造时可以指定其编码集合,例如:
InputStreamReader isr = new InputStreamReader(System.in, “ISO8859_1”)
Eg1:
publicclass TestTrasForm1 {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
try {
OutputStreamWriter osw=new OutputStreamWriter(
new FileOutputStream("E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\dat.text"));
osw.write("你好");
System.out.println(osw.getEncoding());
osw.close();
osw=new OutputStreamWriter(
//参数true表示在源文件的末尾添加,不会覆盖原来的文件里面的内容。
new FileOutputStream("E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\dat.text",true),"ISO8859_1");
osw.write("nihao");
System.out.println(osw.getEncoding());
osw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Eg2:
publicclass TestTransForm2 {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
InputStreamReader isr=new InputStreamReader(System.in);//阻塞式方法,程序既不会停止也不会往前执行,会停在这里等待输入。
BufferedReader br=new BufferedReader(isr);//为什么还要套用一层BufferedReader?readLine方法。
String s=null;
try {
s=br.readLine();
while(s!=null){
//如果输入的字符等于exit(忽略大小写)则程序推出。
if(s.equalsIgnoreCase("exit")){
break;
}
System.out.println(s.toUpperCase());
s=br.readLine();
}
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
数据流&ByteArrayInputStream&ByteArrayOutputStream
l DataInputStream 和 DataOutputStream 分别继承自InputSteam 和 OutputStream,它属于处理流,需要分别“套接”在InputStream 和OutputStream类型的节点流上。
l DataInputStream和DataOutputStream提供了可以存取与机器无关的Java原始类型数据(如:int,double 等)的方法。
l DataInputStream和DataOutputStream的构造方法为:
§ DataInputStream ( InputStream in )
§ DataOutputStream ( OutputStream out )
Eg:
publicclass TestDataStream {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
ByteArrayOutputStream baos=new ByteArrayOutputStream();
DataOutputStream dos=new DataOutputStream(baos);
try {
dos.writeDouble(Math.random());
dos.writeBoolean(true);
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
System.out.println(bais.available());
DataInputStream dis=new DataInputStream(bais);
System.out.println(dis.readDouble());//先进先出,队列。
System.out.println(dis.readBoolean());
dos.close();
dis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Print 流
l PrintWriter和PrintStream 都属于输出流,分别针对与字符和字节。
l PrintWriter和PrintStream提供了重载的print
l Println方法用于多种数据类型的输出。
l PrintWriter和PrintStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息。
l PrintWriter和PrintStream有自动flush功能。
PrintWriter(Writer out)
PrintWriter(Writer out,boolean autoFlush)
PrintWriter(OutputStream out)
PrintWriter(OutputStream out,boolean autoFlush)
PrintStream(OutputStream out)
PrintStream(OutputStream out,booleanautoFlush)
Eg1:
publicclass TestPrintStream1 {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(
"E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\dat.text");
ps = new PrintStream(fos);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(ps!=null){
System.setOut(ps);//重新分配“标准”输出流。输出到ps指定的文件中而不是控制台。
}
int ln=0;
for(char i=0;i<=10000;i++){
System.out.print(i+" ");
ln++;
if(ln==100){
System.out.println();
ln=0;
}
}
}
}
Eg2:
publicclass TestPrintStream2 {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
String s=null;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
FileWriter fw = new FileWriter(
"E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\logfile.log",true);
PrintWriter logPW=new PrintWriter(fw);
while((s=br.readLine())!=null){
if(s.equalsIgnoreCase("exit")){
break;
}
System.out.println(s.toUpperCase());
logPW.println("------");
logPW.println(s);
logPW.flush();//可以自动的flush 可以不写。
}
logPW.println("======"+new Date()+"======");
logPW.flush();
logPW.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Object流
³ 直接将Object写入或读出
² transient关键字
² serializable接口//如果想把某个类的对象序列化必须实现这个接口
² Externalizable 接口
± void writeExternal(ObjectOutput out) throws IOException
± void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
Eg:
publicclass TestObjectIO {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
T t=new T();
t.k=8;
try {
FileOutputStream fos = new FileOutputStream("E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\test.dat");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(t);
oos.flush();
oos.close();
FileInputStream fis=new FileInputStream("E:\\练习\\java\\Workspaces\\Test\\src\\com\\ui\\IO\\test.dat");
ObjectInputStream ois=new ObjectInputStream(fis);
T tRead=(T)ois.readObject();
System.out.println(tRead.i+" "+tRead.j+" "+tRead.d+" "+tRead.k);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//Serializable接口表示可以被序列化的,该接口没有任何方法。用来标记表示这个类的对象可以序列化
class T implements Serializable{
inti=10;
intj=9;
doubled=2.5;
transientintk=2;//transient关键字表示透明的,在序列化的时候不予考虑,即为变量类型默认的值。
}
参考资料:尚学堂。。。。。。