Java中把不同的输入输出源(键盘,文件,网络)抽象为流。
流可分为输入输出流。
流又分为字符流和字节流两大类。
Java输入流主要是由InputStream和Reader作为基类。输出流主要是OutputStream和Writer作为基类。
它们都是抽象基类无法创建实例。
字节流主要以InputStream和OutputStream作为基类。而字符流则主要以Reader和Writer作为基类。
可以从一个特定的IO设备(如键盘,网络)读写的流成为字节流,会和文件关联。也称为低级流(Low Level Stream)。
对一个流进行封装后的流称为处理流,也成为高级流。
InputStream 和 Reader分别有一个用于读取文件的输入流:FileInputStream 和 FileReader,它们都是字节流。
--------------------------------------------------------------------------------
InputStream包含的三个方法:
(1)int read() 读取单个字节。
(2)int read(byte[] b) 最多读取b.length的字节,并将其存储在数组b中。返回实际读取的字节数。
(3)int read(byte[] b,int of,int len) 此时读取的起点从off开始。
Reader的三个方法
(1)int read() 读取单个字符,字符数据可以直接转换为int类型。
(2)int read(char[] cbuf) 最多读取cbuf.length个字符
(3)int read(char[] cbuf,int off,int len) 从off位置开始读。
InputStream和Reader还支持移动记录指针:
(1)void mark(int readAheadLimit): 在记录指针当前位置记录一个标记(mark)
(2)boolean markSupport(): 判断当前流是否支持记录标记;
(3)void reset(): 将记录指针重定位到上一个标记。
(4)long skip(long n): 将记录指针向前移动n个字节/字符
----------------------------------------------------------------------------------
OutputStream 和 Writer都包含如下三个方法:
(1)void write(int c): 将指定字节/字符输出到流中。
(2)void write(byte[]/char[] buf): 将字节数组/字符数组输出到流中
(3)void write(byte[]/char[] buf, int off, int len): 将字节数组/字符数组从off位置开始,长度为len的字节/字符输出到流中。
此外,因为字符流以字符为单位,所以Writer还支持用字符串来代替字符数组。包含如下方法:
(1)void write(Strng str): 将字符串包含的字符输出到流中
(2)void write(Sring str,int off,int len): 将字符串从off位置开始,长度为len的字符输出到流中。
try {
/** 获取文件输入流 */
FileInputStream fis = new FileInputStream(file);
/** 读取文件 */
while ((length = fis.read(buffer)) > 0) {
// 需要将字符数组转化为字符串后输出,不然输出的是乱码,转成字符串后中文仍是乱码
System.out.println("----" + buffer);
System.out.println("----" + new String(buffer, "utf-8"));
System.out.println("----" + new String(buffer, 0, length));// offset
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
============================================
上面介绍了输入输出流的4个抽象基类,并介绍了4个访问文件节点流的方法。使用比较繁琐。
处理流进行输入输出更简单,效率也更高。
通常认为字节流要比字符流更为强大,因为计算机中所以数据都是二进制的,而字节流可以处理所有二进制文件。但转换成字符就复杂了。所以一般:如果输入输出是文本内容则用字符流,如果输入输出是二进制,则用字节流。
四个抽象基类: InputStream OutputStream Reader Writer
对应四个节点流方法: FileInputStream FileOutputStream FileReader FileWriter
处理流 : PrintStream 用来包装InputStream (包括FileInputStream) 如果需要输入文本,最好就用处理流。关闭上层的处理流,系统会自动关闭对应的节点流。
转换流 : InputStreamReader : 把字节流转换成字符输入流 InputStreamWriter 把字节流转换成字符输出流
System.in 代表键盘输入流,但其是Inputstream的实例,使用不方便,可以包装成InputStreamReader 将其转换为字符输入流,普通的Reader读取内容时不方便,可以转化为BufferReader利用BufferReader的readLine()可以一次读取一行。
/** 用转换流就可以不乱码了。windows使用的gbk,linux平台上中文一般utf-8. 根据tmp.txt的编码类型来选择 */
fis = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(fis, "gbk");
BufferedReader br = new BufferedReader(reader);
String readStr = null;
while ((readStr = br.readLine()) != null) {
System.out.println("-----: " + readStr);
}
自动解析编码:
public String convertCodeAndGetText(String str_filepath) {// 转码
File file = new File(str_filepath);
BufferedReader reader;
String text = "";
try {
// FileReader f_reader = new FileReader(file);
// BufferedReader reader = new BufferedReader(f_reader);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream in = new BufferedInputStream(fis);
in.mark(4);
byte[] first3bytes = new byte[3];
in.read(first3bytes);//找到文档的前三个字节并自动判断文档类型。
in.reset();
if (first3bytes[0] == (byte) 0xEF && first3bytes[1] == (byte) 0xBB
&& first3bytes[2] == (byte) 0xBF) {// utf-8
reader = new BufferedReader(new InputStreamReader(in, "utf-8"));
} else if (first3bytes[0] == (byte) 0xFF
&& first3bytes[1] == (byte) 0xFE) {
reader = new BufferedReader(
new InputStreamReader(in, "unicode"));
} else if (first3bytes[0] == (byte) 0xFE
&& first3bytes[1] == (byte) 0xFF) {
reader = new BufferedReader(new InputStreamReader(in,
"utf-16be"));
} else if (first3bytes[0] == (byte) 0xFF
&& first3bytes[1] == (byte) 0xFF) {
reader = new BufferedReader(new InputStreamReader(in,
"utf-16le"));
} else {
reader = new BufferedReader(new InputStreamReader(in, "GBK"));
}
String str = reader.readLine();
while (str != null) {
text = text + str + "/n";
str = reader.readLine();
}
reader.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return text;
}