Java把不同类型的输入、输出,这些输入输出有些是在屏幕上、有些是在电脑文件上,都抽象为流(Stream)

按流的方向,分为输入流与输出流,注意这里的输出输出是相对于程序而言的,如:如对于一个Java程序创建了一个输入流(Input),此时应该是进行读取操作将数据读到程序中。

JAVA输入输出流GB编码 java输入输出流详解_java 输入输出流知识

流既然是用来进行输入输出的,那么在所有的流中可以按每次输入输出的量分成两类流:字节流、字符流。顾名思义字节流每次操作为一个一个字节、字符流则每次读取一个一个字符。

额外的,在字符流中对于一个字符,不同编码方式他也有不同的表现形式,比如汉字,到底是这些字符采用UTF-8(多个字节),还是国标码(2个字节),不同编码对应不同的字节数。所以使用字符流时需要额外指定编码方式。

分成四个超类(很重要):

字节流

字符流

输入流

InputStream

Reader

输出流

OutputStream

Writer

InputStream类

read(),逐字节地以二进制的原始方式读取数据
public int read();        读入一个字节,-1表示无
public int read(byte b[]);            返回读入的字节数
public int read(byte[] b, int off, int len);

OutputStream类

write()方法,它的功能是将字节写入流中

public void write (int b);// 将参数b的低位字节写入到输出流
public void write (byte b[]);// 将字节数组b[]中的全部字节顺序写入到输出流
public void write(byte[] b, int off, int len);// 将字节数组b[]中从off开始的len个字节写入到流中

Output的另外两个方法是flush()及close()。

public void flush (); 刷新缓存,实际写入到文件、网络
public void close(); 关闭流

Reader类

与InputStream类相似,都是输入流,但差别在于Reader类读取的是字符(char),而不是字节。

Reader的重要方法是read()

public int read(); //返回:作为整数读取的字符(需要将int转char),如果已到达流的末尾,则返回 -1
public int read(char b[]);   //返回:读取的字符数
public int read(char[] b, int off, int len);

Writer类

与OutputStream类相似,都是输出流,但差别在于Writer类写入的是字符(char),而不是字节。

Writer的方法有:

public void write (int b);// 将参数b的低两字节写入到输出流
public void write (char b[]);// 将字符数组b[]中的全部字节顺序写入到输出流
public void write(char[] b, int off, int len);// 将字节数组b[]中从off开始的len个字节写入到流中
public void write( String s);// 将字符串写入流中
public void write( String s, int off, int len);// 将字符串写入流中, off为位置,len为长度
public void flush ();// 刷新流
public void close();// 关闭流

既然上面Reader、Writer、InputStream、OutputStream四类是根据每次操作的量以及输入输出划分出来的,那么就有其他的划分方式,划分为:节点流、处理流

节点流:可以向特定的地方(如文件)读写数据,如文件流FileInputStream、内存流ByteArrayInputStream.

处理流:可以对以及存在的流进行操作,也被称为过滤流(Filter),如缓冲处理流BufferedReader

JAVA输入输出流GB编码 java输入输出流详解_输出流_02

上图是就是使用节点流和处理流的例子,先通过FileReader读入文件中的字符串,然后使用处理流对这个流进行处理,有了这个处理流后就不必通过节点流提供的read()一个一个进行读取,BufferedReader这个处理流提供了readLine()方法可以一次读出节点流中的一行。这样的两者结合起来的操作实现了对流的包装(链接)。

JAVA输入输出流GB编码 java输入输出流详解_输出流_03

同时使用节点流和处理流的实际使用例子:

BufferedReader in =
new BufferedReader(new FileReader(file));
BufferedReader in2 =
new BufferedReader(
new InputStreamReader(   //该处理流是字节流通向字符流的桥梁
new FileInputStream(file), “utf-8”));
s = in2.readLine();

从上图和例子看出,处理流构造时总是需要带一个其他流对象作为参数,一个流对象经过其他流的多次包装,称为流的链接。

通过节点流、处理流这样的划分方式,当我们进行I/O操作时,只需使用对应的数据类型对应的流,然后通过处理流进行链接,对流进行层层操作,便可以实现所需要的功能。

常用的节点流:

节点类型

字节流

字符流

File

文件

FileInputStream
FileOutputStream
FileReader
FileWriter
Memory Array

内存数组

ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter
Memory String

字符串

StringReader

StringWriter

Pipe

管道

PipedInputStream

PipedOutputStream

PipedReader

PipedWriter

常用的处理流:

处理类型

字节流

字符流

Buffering

缓冲

BufferInputStream

BufferOutputStream

BufferedReader

BufferedWriter

Filtering

过滤

FilterInputStream

FilterOutputSteam

FilterReader

FilterWriter

Converting between bytes and character

字节流转换为字符流

InputStreamReader

OutputStreamWriter

与字符编码有关

Object Serialization

对象序列化

ObjectInputStream

ObjectOutputStream

Data conversion

基本数据类型转化

DataInputStream

DataOutputStream

Counting

行号处理

LineNumberInputStream

LineNumberReader

Peeking ahead 可回退流

PushbackInputStream

PushbackReader

Pinting 可显示流

PrintStream

PrintWriter

标准输入和输出

平时我们常用的System.in实际上是InputStream类型,而System.out、System.err为PrintStream类型,是一个字符输出流。平时用到的就是流,所以在使用的时候我们经常将System.in用各种处理流封装起来使用。如:

BufferedReader br = newBufferedReader(newInputStreamReader(System.in));

br.readLine();

在jdk1.5后增加了Scanner类,使用起来方便了些。

实例!常见内容(二进制、文本、对象)的读写:

二进制流的读写:

tip:IO中“二进制”指的是除了文本、对象之外的其他内容,在这里是一个比较笼统的概念

import java.io.*;public classDump {public static voidmain(String[]args) {try{
dump(new FileInputStream("aaa.bmp"), //FileInputStream节点流
new FileOutputStream("bbb.bmp"));
}catch(FileNotFoundException fex)
{
fex.printStackTrace();
}catch(IOException ioe)
{
ioe.printStackTrace();
}
}public static void dump(InputStream src, OutputStream dest) //这里使用InputStream、OutputStream类型作为参数
throwsIOException
{
InputStream input= new BufferedInputStream(src); //使用处理流进行包装
OutputStream output = new BufferedOutputStream(dest); //向上转型
byte[] data = new byte[1024];int length = -1;while ((length = input.read(data)) != -1) { //read()将流中数据读取到data中
output.write(data, 0, length);
}
input.close();
output.close();
}
}

字符的读写:

import java.io.*;public classCopyFileAddLineNumber {public static voidmain (String[] args) {//将文件的每一行注释去掉,然后加上行号
String infname = "CopyFileAddLineNumber.java";
String outfname= "CopyFileAddLineNumber.txt";if( args.length >= 1 ) infname = args[0];if( args.length >= 2 ) outfname = args[1];try{
File fin= newFile(infname);
File fout= newFile(outfname);
BufferedReader in= new BufferedReader(newFileReader(fin));
PrintWriter out= new PrintWriter(newFileWriter(fout));int cnt = 0; //行号
String s =in.readLine();while ( s != null) {
cnt++;
s= deleteComments(s); //去掉以//开始的注释
out.println(cnt + ": \t" + s ); //写出
s = in.readLine(); //读入
}
in.close();//关闭缓冲读入流及文件读入流的连接.
out.close();
}catch(FileNotFoundException e1) {
System.err.println("File not found!");
}catch(IOException e2) {
e2.printStackTrace();
}
}static String deleteComments( String s ) //去掉以//开始的注释
{if( s==null ) returns;int pos = s.indexOf( "//");if( pos<0 ) returns;return s.substring( 0, pos );
}
}

序列化与反序列化(要求对象实现Serializable接口)

import java.io.*;class Person implementsSerializable
{
String name;intage;
Person(String name,intage) {this.name=name;this.age=age;
}publicString toString() {return name + "(" + age + ")";
}
}public classSerializeDemo {public static voidmain (String[] args)throwsIOException
{
Person [] ps={new Person("Li",18),new Person("Wang",19)
};
String fileName= "s.temp";//Serialize
ObjectOutputStream output = newObjectOutputStream(newFileOutputStream(fileName) );for(Person p : ps) output.writeObject(p);
output.close();//deserialize
ObjectInputStream input = newObjectInputStream(newFileInputStream(fileName) );
Person p= null;try{while( (p=(Person)input.readObject()) != null) {
System.out.println(p);
}
}catch(ClassNotFoundException ex) {}catch(EOFException eofex) {}
input.close();
}
}