1.流的概念
计算机中的流其实是一种信息转换。它是一种有序流,因此相对于某一对象,通常把对象接受外界的信息输入(input)称为输入流,相应地从对象向外输出(Output)的信息称为输出流,合称为输入/输出流(I/O Streams)。对象间进行信息或者数据的交换时,总是先将对象或数据转换为某种形式的流,再通过流的传输到达目的对象后将流转换为对象数据。所以,可以把流看做是一种数据的载体,通过它可以实现数据交换和传输。
在Java中,流仍是一个类的对象,很多文件的输入/输出操作都以此类的成员方法的方式来提供。
- Java的输入/输出流概述
Java流中分为两种,一种是字节流,另一种是字符流,每种流又分为输入和输出两种,并分别由四个抽象类来表示:InputStream、OutputStream、Reader、Writer。
(1)字节流:从InputStream和OutputStream派生出来的一系列类。这类流以字节(byte)为基本处理单位。
(2)字符流:从Reader和Write派生出的一系列类,这类流以16位Unicode码表示的字符为基本处理单位。
在这四个抽象类中,一些最基本的方法:
1)read()方法:当输入流被打开后,可以从里面读取信息。此方法可以从输入流中分离出一个或多个字节,如果字节没有准备好,则read命令将处于等待状态,直到字节流变为有效,即称为同步访问。在InputStream中的read()方法是个抽象方法,Java允许在InputStream流和Reader流的子类中重构read()方法。
2)write()方法:当输入流被打开后,可以使用write()方法向流中写入数据。Java允许在OutputStream流和Write流的子类中重构write()方法。
3)flush()方法:清空输入流。也就是强制把进程缓存中的数据提交给操作系统。并输出所有被缓存的字节。该方法将把缓存中所有内容强制输出到流中。
4)close()方法:对流操作完毕后,必须要将流对象关闭,此时流对象执行close()方法。close()方法不仅关闭输出流,而且释放与此流有关的所有系统资源。[关闭后的写操作会产生IOException异常。当停止I/O操作时,Java不会自动地清空(flush)和关闭数据流。因此,在I/O操作后,立即关不每一个数据流]
5)I/O中的异常:进行I/O操作时可能会产生I/O异常,这属于非运行时异常,应该在程序中处理。
2. 字节输入/输出流类
- Java的标准输入/输出流
public static final InputStream in;
public static final PrintStream out;
标准输入流System.in通常对应于键盘输入或者由主机环境(或用户)指定的另一个输入源;标准输出流System.out对应于显示器输出或由主机环境(或用户)指定的另一个输出目标。
实例:
public class Test1 {
public static void main(String[] args) throws IOException {
char a;
System.out.println("Please input a char");
a = (char)System.in.read();
System.out.println("The char is: " + a);
}
}
运行结果:
- 文件输入/输出流类:
1. FileInputStream类
FileInputStream类创建一个能从文件读取字节的InputStream,常用的构造方法:
1)FileInputStream(File fileobj):
通过打开一个到实际文件的连接来创建一个FileInputStream,该文件为文件系统的File对象fileobj。
2)FileInputStream(String path):
通过打开一个到实际文件的连接来创建一个FileInputStream,该文件的完整路径名为path。
2. FileOutputStream类
FileOutputStream类创建一个可以向文件写入自己饿的类OutputStream,常用的构造方法:
1)FileOutputStream(File file):
创建一个向指定File对象表示的文件中写入数据的文件输出流。
2)FileOutputStream(String name):
创建一个像具有指定名称的文件中写入数据的输入文件流。
3)FileOutputStream(String name,boolean append):
创建一个像具有指定name的文件中写入数据的输出文件流。如果append为true,文件以设置搜索路径模式打开。
实例:创建一个文件,并输出文件内容
public class IOStreamTest {
public static void main(String[] args) {
File f = new File("G:/in.txt");
FileInputStream fin = null;
FileOutputStream fout = null;
int a = 0;
int i = 0;
String s =" ";
try {
/*通过使用FileInputStream访问文件的一个或多个字
节,或整个文件,为一个文件打开输入流FileInputStream,
须将文件名或文件对象传送给构造方法*/
fin = new FileInputStream(f);
fout =new FileOutputStream("G:/out.txt");
byte[] bufferIn = new byte[1];
/*int read(byte b[],int offset,int len):从offset开始做多可将len个字节的数据读入一个字节数组b中*/
while((a= fin.read(bufferIn, 0, 1)) != -1){ // 文件内容以-1结束
//判断输入字符是否为换行符
if(!"\n".equals(String.valueOf((char)bufferIn[0]))){
s += String.valueOf((char)bufferIn[0]);
}else{
i++; //记录行
//在一行末尾加入数字标识
s = i + s + String.valueOf((char)bufferIn[0]);
//将处理后的字符串以字节形式写入out.txt
fout.write(s.getBytes());
System.out.println(s);
s = " ";
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fin.close();
fout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:
示例中在G盘根目录下创建了文件in.txt,通过FileOutputStream类的fout对象将字符串内容写入文件中,然后通过FileInputStream类的fin对象从文件中读取内容并输出。
- 数据字节输入/输出流类
数据字节输入流(DataInputStream)和数据字节输出流(DataOutputStream)提供一些对Java基本数据类型写入的方法,像读写int、double、和boolean等方法。
一般来说对二进制文件使用DataInputStream流和DataOutputStream流。打开和关闭DataInputStream对象时,其方法与FileInputStream相同:
DataInputStream myData;
FileInputStream myFile;
myFile = new FileInputStream("G:/a.txt");
yData = new DataInputStream(myFile);
从DataInputStream流访问文件,可以是使用成员方法read()。也可以使用其他访问方法读取不同种类的数据,如char readChar()、int readInt()、String readLine()等。其中String readLine()成员方法可以用来一次读取一行字符。
- 对象字节输入/输出流类
ObjectInputStream对象输入流配合DataOutputStream对象输出流就可以实现对象的串行化(Serialization)。
对象的寿命通常随着声称该对象的程序终止而终止。对象通过写出描述自己状态的数值来记录自己,这个过程叫做对象的串行化。串行化的目的是为Java的运行环境提供一组特性,其主要任务是写出对象实例变量的数值。
构造对象的输入/输出流:要串行化一个对象,必须与一定的对象输入/输出流联系起来,通过对象的输出流将对象的状态保存下来,再通过输入流将对象状态恢复。在ObjectInputStream中用readObject()方法可以直接读取一个对象,ObjectOutputStream中用writeObject()方法可以直接将对象保存到输出流中。
- 缓冲字节流
缓冲流是一种字节流,通过把内存缓冲区练到输入/输出流而扩展一个过滤流。该缓冲区允许Java对多个字节同时进行输入/输出操作,因此可以减少访问硬盘次数,提高程序的性能和效率。
1. BufferedInputStream缓冲输入流
BufferedInputStream类允许把任何InputStream类封装成缓冲流。如下有两个构造方法:
1)BufferedInputStream(InputStream in):
生成一种默认缓冲长度的缓冲流,一般缓冲大小为8192个字节。
2) BufferedInputStream(InputStream in,int size):
创建具有指定缓冲区大小为size的BufferedInputStream。
2. BufferedOutputStream缓冲输出流
用flush()方法确保缓冲区内字节数据被写入实际的输出设备,还使所有缓冲的输出字节被写出到基础输出流中。如下有两个构造方法:
1)BufferedOutputStream(OutputStream out):
创建一个新的缓冲输出流,已将数据写入指定的基础输出流。
2)BufferedOutputStream(OutputStream out,int size):
创建一个新的缓冲输出流,已将具有指定缓冲区大小的数据写入指定的基础输出流。
实例:
public class BufferIOStreamEg {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("g:/a.txt");
BufferedInputStream bin = new BufferedInputStream(in, 256);
int len;
byte Array[] = new byte[256];
len = bin.read(Array);
for(int i =0; i < len ;i++){
System.out.print((char)Array[i]);
}
}
}
运行结果:
3. 字符流类
字符流是以字符为单位来操作的,一般用于处理文本数据
- 字符输入/输出流抽象类
1. Reader类
Reader类是处理所有字符流输入类的抽象父类,该类所有方法在异常情况下都会产生IOException异常。
1)读取字符:
①public void read() throws IOException;
②public void read(char cbuf[]) throws IOException;
③public abstract int read(char cbuf[],int off,int len) throws IOException;
2)标记流:
①public boolean markSupported();
②public void mark(int readAheadLimit) throws IOException;
③public void reset() throws IOException;
3)关闭流:
public abstract void close() throws IOException;
4)标记流中的当前位置:
void mark(int readAheadLimit);
5)跳过字符:
skip(long n)
2. Write类
Write类是处理所有字符流输出类的抽象父类,该类所有方法在异常情况下都会产生IOException异常。
1)向输出流写入字符:
①public void write(int c) throws IOException;
②public void write(char cbuf[]) throws IOException;
③public abstract int write(char cbuf[],int off,int len) throws IOException;
④public void write(String str) throws IOException;
⑤public void write(String str,int off,int len) throws IOException;
2)flush():清空输出流,并输出所有被缓存的字节。
3)关闭流:
public abstract void close() throws IOException;
- 文件字符输入/输出流类
1. FileReader类
FileReader类创建了一个可以读取文件内容的Reader类
①FileReader(File file)
②FileReader(FileDescriptor fd):FileDescriptor是文件的完整路径
③FileReader(String fileName):fileName是描述该文件的File对象。
2. FileWrite类
FileWrite类创建了一个可以读取文件内容的Write类
①FileWrite(File file)
②FileWrite(String fileName)
③FileWrite(String fileName,boolean append):
在给出文件名的情况下构造FileWrite对象,若append为true,则输出附加至文件尾。
- 字符输入/输出流类
1. InputStreamReader
InputStreamReader是字节流通向字符流的桥梁。
@Test
public void test6() {
FileInputStream in = null; //文件输入流
InputStreamReader ir = null; //字符输入流
BufferedReader r = null; //字符缓冲流
try {
in = new FileInputStream("g:/b.txt");
ir = new InputStreamReader(in, "utf-8");
r = new BufferedReader(ir);
String str = r.readLine();
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
}
}
2. OutputStream
InputStreamReader是字符流通向字节流的桥梁。
@Test
public void test7() {
FileOutputStream fo = null;
OutputStreamWriter ow = null;
BufferedWriter bw = null;
try {
fo = new FileOutputStream("g:b.txt");
ow = new OutputStreamWriter(fo, "utf-8");
bw = new BufferedWriter(ow);
bw.write("猎场!");
bw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 字符缓冲流:
字符缓冲流BufferedReader和BufferedWrite可用来缓冲Reader和Write流中字符等数据,从而提供字符、数组和行的高效读取和写入。一般豆浆Reader和Write流打包成BufferedReader和BufferedWrite
public class BufferedReaderEg {
public static void main(String[] args) throws IOException {
String bufStr;
int bufInt;
//设置输入端为键盘
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入一个整数:");
bufStr = buf.readLine(); //从键盘上输入数据
bufInt = Integer.parseInt(bufStr);
buf.close();
System.out.println("The Integer is=" + bufInt);
}
}
运行结果: