1、输入流:可以从中读取一个字节。InputStrean

输出流:可以向其中写入一个字节。OutputStream

2、流来源、去处可能是文件,也可能是网络等。

3、由于 Unicode 多个字节表示一个字,所以不可能用流读取 Unicode 编码的文件。因此引入了 Reader 和 Writer 处理他们(基于双字节)。

4、基础的流只有两个:InputStreamOutputStream

abstract class InputStream{

    abstract int read();
 
    abstract int read(byte [] b, int off, int len);
 
    abstract int avaliable();
 
    long skip(long n);
 
    void close();
}

read() 每次读取一个字节,读到最后返回 - 1,字节不可用时会阻塞。

read(byte[] b, int off, int len) 从 off 偏移开始读取字节,读取 len 个,返回实际读取的个数。

avaliable,不阻塞的返回可用字节数,-1 为结尾。

都结束操作后,应该用 close 关闭,否则会耗尽系统资源(比如 Linux 下的 nofile)。

abstract class OutputStream
{
    abstract void write();

    abstract int write(byte [] b, int off, int len);

    void close();

    void flush();
}

write 也是阻塞的写入。

flush 是清空输出流,将缓存物理写入。close 时会隐式调用这个。

5、所有的其他实用流都继承自** InputStream/OutputStream**,一次读取一个字节。


6、字符流用于处理 Unicode,一次读取两个字节,ReaderWriter

abstract class Reader
{
    abstract int read();
}

abstract class Writer
{
    abstract void write(int c);
}

Reader 和 InputStream 基本一致,但是 read 返回的是 Unicode 码元 (0~65535 之间的数),结尾一样返回 - 1。

Writer 也是类似,只不过传入的 c 必须是 Unicode 码。

7、Java SE 5 额外引入了几个接口:Closeable、Flushable、Readable、Appendable

前两个接口就是对应了 close 和 flush 方法。Input/OutputStream、Reader/Writer 都实现了 Closeable,写的还实现了 Flushable。

8、Readable 接口只有一个方法:

Interface Readable{
    int read(CharBuffer cb);
}

这个 CharBuffer 是影射到内存中的可随机访问的块。FileReader、BufferedReader 等都实现了这个方法。

Interface Readable{
    int read(CharBuffer cb);
}

可以追加一个或者多个字节,只有 Writer 实现了它。

9、Java 的流使用组合的方式实现复杂的功能。例如从文件中读取需要使用 FileInputStream,从流中读取整数需要 DataInputStream,但是后者只接受 InputStream 参数而不接受文件名参数,于是:

Interface Readable{
    int read(CharBuffer cb);
}

如果我们希望读取的再快一些,可以在 FileInputStream 上追加包装一个 BufferedInputStream。

10、PushBackInputStream,可以 “回推” 输入流。如果希望预先浏览,还能回退的流,可以用它的 unread(…)方法。

11、ZipInputStream 可以读写 zip 文件,例如我们直接读取 Zip 文件中的 double:

Interface Readable{
    int read(CharBuffer cb);
}

读写 zip 文件需要结合 getNextEntry() 方法,如下:

public void unzip(String zipFileName,String outputDirectory)throws Exception{

	ZipInputStream in=new ZipInputStream(new FileInputStream(zipFileName));

	ZipEntry z;

	while ((z=in.getNextEntry() )!= null)

	{

		System.out.println("unziping "+z.getName());

		if (z.isDirectory())

		{

			String name=z.getName();

			name=name.substring(0,name.length()-1);

			File f=new File(outputDirectory+File.separator+name);

			f.mkdir();

			System.out.println("mkdir "+outputDirectory+File.separator+name);

		}

		else{

			File f=new File(outputDirectory+File.separator+z.getName());

			f.createNewFile();

			FileOutputStream out=new FileOutputStream(f);

			int b;

			while ((b=in.read()) != -1)

				out.write(b);

			out.close();

		}

	}

	in.close();

}

12、OutputStreamWriter:把 Unicode 字符转变为字节流(以借助下层链上的 XXOutputStream 输出到文件、网络等)。

InputStreamReader:将包含字节输入流转变成提供 Unicode 读取的读入器:

InputStreamReader in = new InputStreamReader(new FileInputStream("xx.txt"), "utf-8");
StringBuilder sb = new StringBuilder();
char cbuf[] = new char[1024];
int len = 0;
while((len = in.read(cbuf, 0, cbuf.length))!=-1)
{
    sb.append(cbuf);
}

这貌似也是不同流转化编码的唯一方式。同理,输出别的编码,要使用 OutputStreamWriter:

OutputStreamWriter(OutputStream out, String charsetName)

13、如果只是读写文件(没编码的问题),可以直接使用 FileReader 和 FileWriter,他们都有不需要底层 FileInput/OutputStream 的构造函数:

OutputStreamWriter(OutputStream out, String charsetName)

14、PrintWriter 可以文本格式、数字等方法输出到文件,构造函数中可以带一个 boolean 参数,决定是否启用输出缓冲区,同时,还可以设置文件的字符编码。

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

public class PRTest {
	public static void main(String[] args) {

		PrintWriter out = null;
		try {
			out = new PrintWriter("test.txt", "utf-8");
			out.format("%s: %d", "计算所", 10);
                        out.println("abcabc")

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (out != null) {
				out.close();
			}
		}

	}
}

15、总结:以二进制格式写数据:DataOutputStream,以文本格式写数据:PrintWriter。

16、读取文本数据:BufferedReader(<JDK5) 或者 Scanner(>JDK5)

17、BufferedReader 只能读取单个字符,如果要读数字等格式,最好用 Scanner。

18、可以用文本格式存储对象:例如各个域之间用 | 分开(假定域内不含有 |),则输出的时候用 PrintWriter 写 String,读取的时候用 Scanner 读取一行,然后用 String 分割:

String line = scan.nextLine();
String parts[] = line.split("\\|");

注意 | 输入正则的一部分,需要转义。

19、JDK1.4 之后,引入了** java.nio.Charset**,用语多编码的表示。

20、几种常见的编码:
ISO-8859-1 就是最原始的 ASCII。
ISO-8859-15 1 的基础上,加入法语和荷兰语,并使用欧元符号。
UTF-8 不解释了。。

通过调用 Charset.forname 获得一个编码:

Charset cset = Charset.forname("utf-8");

Java 中的编码名字不区分大小写!

每个编码有很多别名,可以用 aliases() 取得这些别名。

import java.nio.charset.Charset;

public class TestCharSetAlias {

    public static void main(String [] args) {
        Charset cset = Charset.forName("utf-8");
        for(String name: cset.aliases()) {
            System.out.println(name);
        }
    }
}

21、如果不确定 JDK 中有哪些字符集,可以调用 static 方法 availableCharsets 获取所有可用的字符集编码:

import java.nio.charset.Charset;
import java.util.Map;

public class TestCharSetAlias {

    public static void main(String [] args) {
        Map<String, Charset> map = Charset.availableCharsets();
        for(String name: map.keySet()) {
            System.out.println(name);
        }
    }
}
Big5
Big5-HKSCS
COMPOUND_TEXT
EUC-JP
EUC-KR
GB18030
GB2312
GBK
IBM-Thai
IBM00858
IBM01140
IBM01141
IBM01142
IBM01143
IBM01144
IBM01145
IBM01146
IBM01147
IBM01148
IBM01149
IBM037
IBM1026
IBM1047
IBM273
IBM277
IBM278
IBM280
IBM284
IBM285
IBM297
IBM420
IBM424
IBM437
IBM500
IBM775
IBM850
IBM852
IBM855
IBM857
IBM860
IBM861
IBM862
IBM863
IBM864
IBM865
IBM866
IBM868
IBM869
IBM870
IBM871
IBM918
ISO-2022-CN
ISO-2022-JP
ISO-2022-JP-2
ISO-2022-KR
ISO-8859-1
ISO-8859-13
ISO-8859-15
ISO-8859-2
ISO-8859-3
ISO-8859-4
ISO-8859-5
ISO-8859-6
ISO-8859-7
ISO-8859-8
ISO-8859-9
JIS_X0201
JIS_X0212-1990
KOI8-R
KOI8-U
Shift_JIS
TIS-620
US-ASCII
UTF-16
UTF-16BE
UTF-16LE
UTF-32
UTF-32BE
UTF-32LE
UTF-8
windows-1250
windows-1251
windows-1252
windows-1253
windows-1254
windows-1255
windows-1256
windows-1257
windows-1258
windows-31j
x-Big5-HKSCS-2001
x-Big5-Solaris
x-euc-jp-linux
x-EUC-TW
x-eucJP-Open
x-IBM1006
x-IBM1025
x-IBM1046
x-IBM1097
x-IBM1098
x-IBM1112
x-IBM1122
x-IBM1123
x-IBM1124
x-IBM1381
x-IBM1383
x-IBM33722
x-IBM737
x-IBM833
x-IBM834
x-IBM856
x-IBM874
x-IBM875
x-IBM921
x-IBM922
x-IBM930
x-IBM933
x-IBM935
x-IBM937
x-IBM939
x-IBM942
x-IBM942C
x-IBM943
x-IBM943C
x-IBM948
x-IBM949
x-IBM949C
x-IBM950
x-IBM964
x-IBM970
x-ISCII91
x-ISO-2022-CN-CNS
x-ISO-2022-CN-GB
x-iso-8859-11
x-JIS0208
x-JISAutoDetect
x-Johab
x-MacArabic
x-MacCentralEurope
x-MacCroatian
x-MacCyrillic
x-MacDingbat
x-MacGreek
x-MacHebrew
x-MacIceland
x-MacRoman
x-MacRomania
x-MacSymbol
x-MacThai
x-MacTurkish
x-MacUkraine
x-MS932_0213
x-MS950-HKSCS
x-MS950-HKSCS-XP
x-mswin-936
x-PCK
x-SJIS_0213
x-UTF-16LE-BOM
X-UTF-32BE-BOM
X-UTF-32LE-BOM
x-windows-50220
x-windows-50221
x-windows-874
x-windows-949
x-windows-950
x-windows-iso2022jp