目录:
一、什么是IO流
二、流的分类
1、节点流
2、处理流
2.1缓冲流
2.2转换流
2.3数据流
2.4Print流(打印流)
2.5 Object流(对象流)
一、什么是IO流
IO流即是输入(Input)输出(Output)流,输入和输出的方向是针对程序而言的,比如现在要读取文件内容,那么就是输入流,是对于程序而言的。流其实就是传输数据用的,流位于java.io包当中,最主要的就是字符流和字节流,Java当中字符是两个字节。关于流的类都继承自下面抽象类
注意这几个是抽象类,无法实例化。
二、流的分类
一般按照处理数据单位分为字节流和字符流,这里按照功能分类,分成节点流和处理流。
1、节点流
可以看到节点流有处理文件的,有处理内存数组(Memory Array)的,内存字符串的、以及Pipe管道的。
下面以处理File为例,先介绍字节流:
/**
* 读取路径下的文件内容,显示在控制台
*/
package com.zhoucy.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestFileInputStream {
public static void main(String[] args) {
int b = 0;
FileInputStream in = null;
try{
in = new FileInputStream("e:/java/io/DataTest.java");
} catch(FileNotFoundException e) {
System.out.println("找不到指定文件");
System.exit(-1);
}
try{
long num = 0;
while((b=in.read())!=-1){
System.out.print((char)(b));
num++;
}
System.out.println();
System.out.println("共读取了"+num+"个字节");
in.close();
} catch (IOException e) {
System.out.println("文件读取错误");
System.exit(-1);
}
}
}
输出结果就不贴了,就是将文件内容打印出来。
/**
* 输入参数args[0]、args[1],将前面的文件拷贝到后面的文件中
* 完成复制拷贝的功能
*/
package com.zhoucy.io;
import java.io.*;
public class TsetFileOutputStream {
public static void main(String[] args) {
int b = 0;
long num = 0L;
FileInputStream in = null;
FileOutputStream out = null;
try{
in = new FileInputStream(args[0]);
out = new FileOutputStream(args[1]);
while((b=in.read())!=-1){
out.write(b);
}
in.close();
out.close();
} catch (IOException e) {
System.out.println("something is wrong!");
System.exit(-1);
}
System.out.println("文件已复制");
}
}
该例在eclipse中运行,先在 Run<<Run Configurations<<Arguments中设置好传给main的参数,多参数用空格隔开。运行结果是在指定的args[1]路径下复制一份args[0]路径下指定的文件。
下面用字符流完成相同拷贝功能:
package com.zhoucy.io;
import java.io.*;
public class TestFileReader {
public static void main(String[] args) {
int b = 0;
FileReader fr = null;
FileWriter fw = null;
try{
fr = new FileReader(args[0]);
fw = new FileWriter(args[1]);
while((b=fr.read())!=-1){
fw.write(b);
}
fr.close();
fw.close();
} catch (FileNotFoundException e) {
System.out.println("找不到指定文件");
} catch (IOException e1) {
System.out.println("文件读取错误");
}
System.out.println("文件复制成功");
}
}
同样是将指定路径下的文件复制一份到args[1]指定的路径下。
2、处理流
2.1 缓冲流
缓冲流要套接在相应的节点流上,对读写的数据提供缓冲的功能,提高读写效率,并且在缓冲流上,有一些新的方法可供使用。
BufferedReader提供了readLine方法,用以读取一行字符串,BufferedWriter提供了newLine用于写入一个行分隔符。对于输出的缓冲流,会将泻出去的数据先在内存中缓存,使用flush方法会使内存中的数据立刻写出。
package com.zhoucy.io;
import java.io.*;
public class TestBufferStream {
public static void main(String[] args) {
try {
FileInputStream fis =
new FileInputStream("e:/java/io/test.java");
BufferedInputStream bis =
new BufferedInputStream(fis);
int c = 0;
System.out.println((char)bis.read());
System.out.println((char)bis.read());
bis.mark(30);//做标记
for(int i=0;i<=10 && (c=bis.read())!=-1;i++){
System.out.print((char)c+" ");
}
System.out.println();
bis.reset();//回到做标记的地方(类似于C文件指针归位)
for(int i=0;i<=10 && (c=bis.read())!=-1;i++){
System.out.print((char)c+" ");
}
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
上例是读取test.java这个文件里面的内容,使用缓冲流,套接在字节流上。其中mark和reset方法是成对使用的,mark先标记一下,类似于C语言的文件指针,先标记在调用mark的地方,后面调用reset的时候,使文件指针回到调用mark标记的地方,(java里应该不叫文件指针,但是原理感觉一样)mark后面的参数,是表示,标记以后,继续读取内容,但是不能超过mark的参数指定的字符数,超过以后,mark标记就失效了,reset也就没用了。
test.java内容是:
class Animal {
String name;
Animal(String name) {
this.name = name;
}
public void info() {
System.out.println("I am Animal");
}
}
读取的结果是:
下面举一个字符缓冲流例子:
package com.zhoucy.io;
import java.io.*;
public class TestBufferedReWr {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try{
fr = new FileReader("e:/java/io/br.txt");
fw = new FileWriter("e:/java/io/br.txt");
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw = new BufferedWriter(fw);
String s;
for(int i=0;i<100;i++){
s = String.valueOf(Math.random());
bw.write(s);
bw.newLine();
}
bw.flush();
for(int i=0;i<10;i++) {
s = br.readLine();
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
该例是往br.txt文件当中写入100行随机数,再从br.txt文件当中读取10行打印到控制台。
执行完以后,br.txt有100行随机数据,打印台信息如下:
2.2 转换流
用于将字节数据转换成字符数据,下例:
/**
* 输入英文字符串,转成大写输出
* 输入exit退出
*/
package com.zhoucy.io;
import java.io.*;
public class TestTransForm {
public static void main(String[] args) {
try{
//从控制台输入
InputStreamReader isr = new InputStreamReader(System.in);
//转成字符流
BufferedReader br = new BufferedReader(isr);
String s;
s = br.readLine();
while(s!=null) {
if(s.equalsIgnoreCase("exit")) break;
System.out.println(s.toUpperCase());
s = br.readLine();
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.3 数据流
package com.zhoucy.io;
import java.io.*;
public class TestDataArray {
public static void main(String[] args) {
ByteArrayOutputStream baos =
new ByteArrayOutputStream();
DataOutputStream dos =
new DataOutputStream(baos);
try {
dos.writeDouble(Math.random());
dos.writeBoolean(true);
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
//返回该字节数组剩余的字节数8+1等于9字节
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) {
e.printStackTrace();
}
}
}
2.4 打印流
这两项的输出操作不会抛出异常,并且有自动flush功能。
例1:往指定文件打印
package com.zhoucy.io;
import java.io.*;
public class TestPrintStream1 {
public static void main(String[] args) {
PrintStream ps = null;
try {
FileOutputStream fos =
new FileOutputStream("e:/java/io/dat1.txt");
ps = new PrintStream(fos);
} catch (IOException e) {
e.printStackTrace();
}
if(ps != null){
System.setOut(ps);//往指定的流里面打印
}
int ln = 0;
for(char c = 0; c <= 100; c++){
System.out.print(c+ " ");
if(ln++ >=30){
System.out.println();
ln = 0;
}
}
}
}
例2:打印指定文件的内容到控制台
//打印文件内容
package com.zhoucy.io;
import java.io.*;
public class TestPrintStream2 {
public static void main(String[] args) {
String filename = args[0];
if(filename!=null){
list(filename,System.out);
}
}
public static void list(String f,PrintStream fs){
try {
BufferedReader br =
new BufferedReader(new FileReader(f));
String s = null;
while((s=br.readLine())!=null){
fs.println(s);
}
br.close();
} catch (IOException e) {
fs.println("无法读取文件");
}
}
}
结果就不贴了,把参数传给args[0]就行了。
例3:把用户在控制台所做的操作打印到日志文件当中去,程序功能还是输入字母串就输出大写字母串,但是把用户的所有输入和日期记录到后台日志文件。
//将控制台做的操作打印记录到log文件里面
package com.zhoucy.io;
import java.util.*;
import java.io.*;
public class TestPrintStream3 {
public static void main(String[] args) {
String s = null;
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
try {
FileWriter fw = new FileWriter
("e:/java/io/_log.log", true); //Log4J
PrintWriter log = new PrintWriter(fw);
while ((s = br.readLine())!=null) {
if(s.equalsIgnoreCase("exit")) break;
System.out.println(s.toUpperCase());
log.println("-----");
log.println(s.toUpperCase());
log.flush();
}
log.println("==="+new Date()+"===");
log.flush();
log.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.5 Object流(对象流)
import java.io.*;
public class TestObjectIO {
public static void main(String args[]) throws Exception {
T t = new T();
t.k = 8;
FileOutputStream fos = new FileOutputStream("d:/share/java/io/testobjectio.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(t);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("d:/share/java/io/testobjectio.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
T tReaded = (T)ois.readObject();
System.out.println(tReaded.i + " " + tReaded.j + " " + tReaded.d + " " + tReaded.k);
}
}
class T
implements Serializable//标记性接口,没有方法,告知编译器,表示该类可以被序列化
{
int i = 10;
int j = 9;
double d = 2.3;
//transient修饰的成员变量在序列化的时候不予考虑,
//序列化之后输出对象,该值为0
transient int k = 15;
}