Java-IO流(四)-字符流(FileReader、FileW
2018-07-21 本文已影响14人
码农随想录
字节流读取字符的问题
一次读一个字节。这样对中文是无法判断。怎么解决呢?一个中文默认是两个字节
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 需求1:通过流写一个篇文章,里面有中文。"你好你好"。indexOf('好');
*/
// writeCNText();
/*
* 需求2:一篇文章中出现了多少个好字。读取数据。判断好字并计数。
* 思路:读取一个文本,获取内容判断好字。
*/
readCNText();
}
public static void readCNText() throws IOException {
FileInputStream fis = new FileInputStream("tempfile/cn.txt");
//一次读一个字节。这样对中文是无法判断。怎么解决呢?一个中文默认是两个字节。
//读取所有的字节,存储起来(字节数组),变成字符串。然后找指定的字符。
// byte[] buf = new byte[4];
// int len = 0;
// while((len=fis.read(buf))!=-1){
// String str = new String(buf,0,len);
// System.out.println(str);
// }
// int ch = 0;
// while((ch=fis.read())!=-1){
// System.out.println(ch);
// }
int ch = fis.read();
System.out.println("读取一个字节:"+ch);
int ch1 = fis.read();
System.out.println("读取一个字节:"+ch1);
fis.close();
}
public static void writeCNText() throws FileNotFoundException, IOException {
FileOutputStream fos = new FileOutputStream("tempfile/cn.txt");
fos.write("你好你好".getBytes());
fos.close();
}
}
编码表
编码表:其实就是生活中文件和计算机二进制的对应关系表。
1,ascii: 一个字节中的7位就可以表示。对应的字节都是正数。0-xxxxxxx
2,iso8859-1:拉丁码表 latin,用了一个字节用的8位。1-xxxxxxx 负数。
3,GB2312:简体中文码表。6,7仟的中文和符号。用两个字节表示。两个字节都是开头为1 两个字节都是负数。
GBK:目前最常用的中文码表,2万的中文和符号。用两个字节表示,一部分文字,第一个字节开头是1,第二字节开头是0
GB18030:
4, unicode:国际标准码表:无论是什么文字,都用两个字节存储。Java中的char类型用的就是这个码表。char c = 'a';占两个字节。
在Java中,字符串是按照系统默认码表来解析的。简体中文版 字符串默认的码表是GBK。
5,UTF-8:基于unicode,一个字节就可以存储数据,不要用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入了编码信息(后期到api中查找)。
能识别中文的码表:GBK UTF-8 正因为识别中文码表不唯一,涉及到了编码解码问题。
对于我们开发而言;常见的编码 GBK UTF-8 ISO8859-1
文字--->二进制(数字) :编码。
二进制(数字)--->文字 : 解码。
FileReader读取字符流
之前都是FileInputStream 用于读取字节流,FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。
查阅FileInputStream api说明中是否有相关的提示呢?发现一个新名词。
字符流:之前用的都是字节流,用于操作的都是字节数据,字符流,专门用于操作字符数据的流对象。
索引了api中的提到的 FileReader对象。发现这个对象是一个操作字符文件的便捷类,内部类使用默认的字符集解码+默认的字节缓冲区。
其中,提到了一个如果需要修改这些值(指定码表,或者缓冲区等)需要查阅InputStreamReader。
目前为了解决当前问题,不需要,只需要使用默认即可。
使用FileReader时,了解它的功能,看它所属的体系顶层。Reader。
Reader:读取字符流的抽象超类。read():读取单个字符并返回, read(char[]):将数据读取到数组中,并返回读取的个数。
FileReader : 字节读取流+默认编码表。
字符流:为了便于操作数据中的字符数据。原理: 字节流+编码表。
字符流的两个基类。
Reader:read()读取字符。
|-
Writer(Reader的另请参见):写入字符。
|-
字节流操作的是字节数组(byte[]);字符流操作的是字符数组(char[])。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 解决需求2问题:
* 使用FileReader。
*
*/
System.out.println("-----------读取字符-------------");
readCNTextByReader();
}
public static void readCNTextByReader() throws IOException {
//创建一个读取字符文件的读取流对象。FileReader。
FileReader fr = new FileReader("tempfile/cn.txt");//这个流的底层使用的是FileInputStream
// int ch = fr.read();
// System.out.println("读取一个字符:"+ch);
// int ch1 = fr.read();//一次读取一个中文,读取多个字节查表转成中文。
// System.out.println("读取一个字符:"+(char)ch1);
int ch = 0;
int count = 0;
while((ch=fr.read())!=-1){
if(ch=='好'){
count++;
}
}
System.out.println("count="+count);
fr.close();
}
}
FileWriter写入字符文件
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//演示FileWriter 用于操作文件的便捷类。
FileWriter fw = new FileWriter("tempfile/fw.txt");
fw.write("你好谢谢再见");//这些文字都要先编码。都写入到了流的缓冲区中。
fw.flush();
fw.close();
/*
* flush()和close()的区别?
*
* flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。
* close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。
*
* 如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由close完成刷新并关闭。
*
*
*/
}
}