在java中定义了多个流类:按照流的方向分为输入流和输出流;按照处理数据单位的不同分为字节流和字符流;按照处理的功能不同分为节点流和处理流。java中的流很多,但是常用的不多。最常用的java流有FileInputStream、FileOutputStream、FileReader、FileWriter。从input和output我们可以知道这四个流中谁是输入流谁是输出流,以Stream为后缀的为节点流,以Reader为后缀的为处理流。所谓处理流就是指在节点流或处理流上在套接一个流,节点流就好比是一个水管,处理流是比套在节点流这个水管上的更粗的水管。在处理流中最常用的还有BufferedReader和BufferedWriter。下面通过例子来看看这几个流的功能:这几个例子的注释非常详细,所以我就不多介绍了。
先看一个有关文件的例子:
import java.io.File;
import java.io.IOException;
public class Demo0 {
public static void main(String args[]) throws IOException
{
// File f=new File("e:"+File.separator+"aa"+File.separator+"abc.txt");//在任何系统状态下建立文件句柄
// File f=new File("e://aa//abc.txt");//在windows系统下建立文件句柄
File f=new File("e:/aa/abc.txt");//适用于Unix系统
f.createNewFile();//创建文件
System.out.println(f.getName());//得到文件的名称
System.out.println(f.getAbsolutePath());//得到文件的绝对路径
System.out.println(f.isFile());//判断文件是不是标准文件
System.out.println(f.isDirectory());//判断文件是不是目录
/*
* 判断文件是否存在,如果存在则删除,如果不存在则新建
*/
if(f.exists())
{
f.delete();
}
else
{
f.createNewFile();
}
}
}
看一个有关FileInputStream例子:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class Demo5 {
public static void main(String args[])
{
File f=new File("e://aa//abc.txt");//将要从哪个文件中读取数据就将哪个文件建立句柄
InputStream input=null;//创建输入流(这个输入流必须放在try括号的外面)
try {
input=new FileInputStream(f);//将输入流指向要读取的文件
} catch (FileNotFoundException e) {
e.printStackTrace();
}
byte str[]=new byte[1024];//创建字节数组,用来盛放从输入流读取的信息
int x=0;
int count=0;
for(int i=0;i<str.length;i++)
{
try {
if((x=input.read())!=-1)//判断是否到文件尾,如果到文件尾就返回-1
{
str[i]=(byte)x;//因为x的值是int类型所以要进行数据转换
count++;//用来计算读入了多少个字节,以便下面进行操作
}
else
{
break;//如果到达文件尾就返回退出循环
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
input.close();//关闭输入流
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(new String(str,0,count));//将字节数组转换成字符串输出
}
}
关于FileOutputStream例子
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Demo4 {
public static void main(String args[]) throws FileNotFoundException
{
File f=new File("e://aa//abc.txt");//向那个文件中写入数据就显得到这个文件的句柄
OutputStream out=new FileOutputStream(f);//新建一个通向f文件的输出流
String xinxi="Hello 你好*****";//要输出的信息
byte b[]=xinxi.getBytes();//将要输出的信息转换成字节数组
try {
out.write(b);//将信息写入文件中
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out.close();//关闭输出流
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
关于FileReader的例子
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class Demo7 {
public static void main(String args[])
{
File f=new File("e://aa//abcd.txt");//从哪个文件读入数据,就获得该文件的句柄
Reader in=null;//创建输入流
try {
in=new FileReader(f);//将输入流指向要从哪个文件读入数据的我文件
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//不能输出汉字
byte[] str=new byte[1024];//建立字节数组用来存放读入的数据
int x=0;
int count=0;
for(int i=0;i<str.length;i++)
{
try {
if((x=in.read())!=-1)//判断是否到文件尾,如果到文件尾就返回-1
{
str[i]=(byte)x;
count++;
}
else
{
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(count);
System.out.println(new String(str,0,count));
//可以输出汉字
// char[] chr=new char[1024];
// int x1=0;
// try {
// x1=in.read(chr);
// } catch (IOException e) {
// e.printStackTrace();
// }
// System.out.println(new String(chr,0,x1));
// System.out.println(x1);
// try {
// in.close();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
}
关于FileWriter的例子
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Demo6 {
public static void main(String args[])
{
File f=new File("e://aa//abcd.txt");//将要向哪个文件输出信息就获得哪个文件的句柄
String str="Hello 你好***";//要向文件输出的字符串信息
char[] chr={'a','b','c','d'};//向文件输出的字符数组信息
Writer out=null;//创建输出流通道
try {
out=new FileWriter(f);//将输出流通道指向要输出的文件
} catch (IOException e) {
e.printStackTrace();
}
try {
out.write(str);//将字符串数组的信息写到文件中
out.write(str,2,4);//将字符串数组的一部分信息写到文件中
out.write(chr);//将字符数组的信息写到文件中
} catch (IOException e) {
e.printStackTrace();
}
try {
out.close();//关闭输出流
} catch (IOException e) {
e.printStackTrace();
}
}
}
关于BufferedReader的例子
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Demo1 {
public static void main(String args[])
{
BufferedReader buf=null;//创建缓冲输入流,可以接受汉字
buf=new BufferedReader(new InputStreamReader(System.in));//将缓冲输入流通道指向控制台
String str=null;//盛放从控制台接受到的信息
System.out.println("请输入内容:");
try {
str=buf.readLine();
buf.close();//关闭输出流
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("输出内容:"+str);
}
}
java流有很多常用的也就这几种。仔细想想其实他们有一个共点:
获得文件句柄
建立通道
读/写数据
关闭通道
流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样,如下图:
Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的:
在这其中InputStream和OutputStream在早期的Java版本中就已经存在了,它们是基于字节流的,而基于字符流的Reader和Writer是后来加入作为补充的。以上的层次图是Java类库中的一个基本的层次体系。
在这四个抽象类中,InputStream和Reader定义了完全相同的接口:
int read() int read(char cbuf[]) int read(char cbuf[], int offset, int length) |
而OutputStream和Writer也是如此:
int write(int c) int write(char cbuf[]) int write(char cbuf[], int offset, int length) |
这六个方法都是最基本的,read()和write()通过方法的重载来读写一个字节,或者一个字节数组。
更多灵活多变的功能是由它们的子类来扩充完成的。知道了Java输入输出的基本层次结构以后,本文在这里想给大家一些以后可以反复应用例子,对于所有子类的细节及其功能并不详细讨论。
import java.io.*;
|
对于上面的例子,需要说明的有以下几点:
1. BufferedReader是Reader的一个子类,它具有缓冲的作用,避免了频繁的从物理设备中读取信息。它有以下两个构造函数:
BufferedReader(Reader in) BufferedReader(Reader in, int sz) |
这里的sz是指定缓冲区的大小。
它的基本方法:
void close() //关闭流 void mark(int readAheadLimit) //标记当前位置 boolean markSupported() //是否支持标记 int read() //继承自Reader的基本方法 int read(char[] cbuf, int off, int len) //继承自Reader的基本方法 String readLine() //读取一行内容并以字符串形式返回 boolean ready() //判断流是否已经做好读入的准备 void reset() //重设到最近的一个标记 long skip(long n) //跳过指定个数的字符读取 |
2. InputStreamReader是InputStream和Reader之间的桥梁,由于System.in是字节流,需要用它来包装之后变为字符流供给 BufferedReader使用。
3. PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
这句话体现了Java输入输出系统的一个特点,为了达到某个目的,需要包装好几层。首先,输出目的地是文件IODemo.out,所以最内层包装的是FileWriter,建立一个输出文件流,接下来,我们希望这个流是缓冲的,所以用BufferedWriter来包装它以达到目的,最后,我们需要格式化输出结果,于是将PrintWriter包在最外层。
Java提供了这样一个功能,将标准的输入输出流转向,也就是说,我们可以将某个其他的流设为标准输入或输出流,看下面这个例子:
import java.io.*; public class Redirecting { BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); |
在这里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.*; public class Logon implements Serializable {
int seconds = 5; |
类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方法就可以了。
需要说明一点,对象序列化有一个神奇之处就是,它建立了一张对象网,将当前要序列化的对象中所持有的引用指向的对象都包含起来一起写入到文件,更为奇妙的是,如果你一次序列化了好几个对象,它们中相同的内容将会被共享写入。这的确是一个非常好的机制。它可以用来实现深层拷贝。
关键字transient在这里表示当前内容将不被序列化,比如例子中的密码,需要保密,所以没有被写入文件。
对Java的输入输出功能,就浅浅的介绍到这里,本文的目的只是开一个好头,希望能让大家对Java输入输出流有个基本的认识。