【目标:字符流】
1,需求:读取一个中文。 发现字节流可以读取就是麻烦。 通过api FileReader,从而了解父类Reader。
提到了编码表。★★★★
编码表:其实就是生活中文件和计算机二进制的对应关系表。
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
文字—>二进制(数字) :编码。
二进制(数字)—>文字 : 解码。2,演示FileReader。 3,演示FileWriter。 4,如果要指定具体的编码。 需要使用转换流。 5,转换流和子类的区别。 OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。 字符转换流原理:字节流+编码表。
FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。
当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
FileReader fr = new FileReader("a.txt");
这三句代码的功能是一样的,其中第三句最为便捷。
注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。
什么时候用子类呢?
条件:
1,操作的是文件。
2,使用默认编码。
字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader
字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter
6,练习:读取一个已有的中文文件(GBK),将数据转成UTF-8写入到另一个文件中。★★★★★
【学习结果】
1,如何通过api中找打所需的对象。一定要自己学会查找动作。★★★★★
2,编码中的细节:常用的码表有哪个?常用码表编码的特点。★★★★★
3,转换流和子类的区别?★★★★★
4,把转换流的案例代码体现出来。
5,动手完成练习。
------------------------
【阶段三】
【目标:字符流的缓冲区对象】
1,自定义字符数数组作为缓冲区是可以的,之所以使用体系给定的缓冲区对象是因为该对象中提供了操作缓冲区的方法。
如果不需要使用这些方法,完成可以通过自定义的缓冲区提高效率。
2,BufferedReader: readLine();
BufferedWriter: newLine();
3,通过缓冲区进行文件的复制。
4,思考题;字符流可以复制图片吗?
【学习结果】
1,使用缓冲区复制文本文件。
2,readLine方法的原理。
FileReader
一篇文章中出现了多少个好字。读取数据,使用了字符流。
public class CharStreamDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 需求1:通过流写一个篇文章,里面有中文。"你好你好"。indexOf('好');
*/
// writeCNText();
/*
* 需求2:一篇文章中出现了多少个好字。读取数据。判断好字并计数。
* 思路:读取一个文本,获取内容判断好字。
*/
readCNText();
/*
* 解决需求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();
}
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();
}
}
演示FileWriter
//演示FileWriter 用于操作文件的便捷类。
FileWriter fw = new FileWriter("tempfile\\fw.txt");
fw.write("你好谢谢再见");//这些文字都要先编码。都写入到了流的缓冲区中。
fw.flush();
fw.close();
/*
* flush()和close()的区别?
*
* flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。
* close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。
*
* 如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由close完成刷新并关闭。
*
*
*/
演示转换流,和子类的区别。★★★★★
public class TransStreamDemo {
/**
* @param args
* @throws IOException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws Exception {
// writeCN();
readCN();
/*
总结:
发现继承关系是这样的。
OutputStreamWriter:
|--FileWriter:
InputStreamReader:
|--FileReader;
父类和子类的功能有什么区别呢?
OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。
字符转换流原理:字节流+编码表。
FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。
当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
FileReader fr = new FileReader("a.txt");
这三句代码的功能是一样的,其中第三句最为便捷。
注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。
什么时候用子类呢?
条件:
1,操作的是文件。
2,使用默认编码。
字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader
字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter
*/
}
public static void readCN() throws IOException {
//创建InputStreamReader对象。
InputStreamReader isr = new InputStreamReader(new FileInputStream("tempfile\\u8cn.txt"),"UTF-8");
char[] buf = new char[1024];
int len = isr.read(buf);
System.out.println(new String(buf,0,len));
isr.close();
}
//读取中文。
public static void readCN_no() throws IOException {
// 使用FileReader没出来,因为文件是UTF-8编码。读取UTF-8字节时,用该指定用UTF-8解码。
// 说明需要指定码表。那就需要使用InputStreamReader。
FileReader fr = new FileReader("tempfile\\u8cn.txt");
// int ch = (char)fr.read();
// System.out.println((char)ch);
char[] buf = new char[1024];
int len = fr.read(buf);
System.out.println(new String(buf,0,len));//浣犲ソ
fr.close();
}
public static void writeCN() throws Exception {
//需求:既然识别中文的码表有两个,GBK UTF-8
//能不能将中文数据按照utf-8的方式进行文件的存储呢?
//还能使用FileWriter吗?不能使用了,因为FileWriter中默认的是GBK
//通过FileWriter的api描述,要指定编码表这些值,需要使用OutputStreamWriter
//OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
//它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("tempfile\\u8cn.txt"),"utf-8");
osw.write("你好");//写入缓冲区。
osw.close();
}
}
字符流缓冲区对象的使用
public class CharStreamBufferedTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 字符流中是否有提供缓冲区中。
* 注意:其实自定义数组就可以解决问题缓冲区问题并提高效率。
* 为什么还要使用流中的缓冲区对象呢?因为缓冲区对象中除了封装数组以外,
* 还提供了更多的操作缓冲区数据的方法。
* BufferedReader BufferedWriter
*
* 讲解字符流缓冲区中的特有方法。
* 操作字符数据时,有一个文本特有的表形实行 :行(hang)
* 操作行的方法。
* BufferedReader:readLine():一次读取一行。
* BufferedWriter:
*/
copyTextByBuffer();
// readText();
// writeText();
}
public static void writeText() throws IOException {
BufferedWriter bufw = new BufferedWriter(new FileWriter("tempfile\\test24_buf.txt"));
for(int x=1; x<=4; x++){
bufw.write(x+"-itcast");
bufw.newLine();
bufw.flush();
}
bufw.close();
}
public static void readText() throws IOException {
BufferedReader bufr = new BufferedReader(new FileReader("Test24.java"));
String line = null;
while((line=bufr.readLine())!=null){
System.out.println(line);
}
// String line = bufr.readLine();
// System.out.println("-"+line+"-");
// String line1 = bufr.readLine();
// System.out.println("-"+line1+"-");
bufr.close();
}
public static void copyTextByBuffer() throws IOException {
BufferedReader bufr = new BufferedReader(new FileReader("Test24.java"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("tempfile\\test24_bufcopy.txt"));
//循环读写一行数据。
String line = null;
while((line=bufr.readLine())!=null){
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
}
}
通过字符流复制文件
public class CopyTextFileTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 练习:复制文本文件。
* 思路:
* 1,既然是文本涉及编码表。需要用字符流。
* 2,操作的是文件。涉及硬盘。
* 3,有指定码表吗?没有,默认就行。
* 操作的是文件,使用的 默认码表。使用哪个字符流对象。直接使用字符流操作文件的便捷类。FileReader FileWriter
*/
copyTextFile();
}
public static void copyTextFile() throws IOException {
//1,明确源和目的。
FileReader fr = new FileReader("Test24.java");
FileWriter fw = new FileWriter("tempfile\\test24_copy.txt");
//2,为了提高效率。自定义缓冲区数组。字符数组。
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1){
fw.write(buf,0,len);
}
//2,循环读写操作。效率低。
// int ch = 0;
// while((ch=fr.read())!=-1){
// fw.write(ch);
// }
//3,关闭资源。
fw.close();
fr.close();
}
}
熟悉了字节流 输入(InputStream)和输出(OutputStream),
解决文件的操作(FileInputStream,FileOutputStream),
同时还提高了效率(BufferedInputStream,BufferedOutputStream)。
在操作数据过程中,字节流可以操作所有数据,现在有一个新的需求。
比如;一篇文章中出现了多少个好字。读取数据。判断好字并计数。
编码表:其实就是生活中文件和计算机二进制的对应关系表。
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
文字—>二进制(数字) :编码。
二进制(数字)—>文字 : 解码。
了解到操作文字数据是需要-编码表配合。
查阅FileInputStream api说明中是否有相关的提示呢?发现一个新名词。
字符流:之前用的都是字节流,用于操作的都是字节数据,字符流,专门用于操作字符数据的流对象。
索引了api中的提到的 FileReader对象。发现这个对象是一个操作字符文件的便捷类,内部类使用默认的字符集解码+默认的字节缓冲区。
其中,提到了一个如果需要修改这些值(指定码表,或者缓冲区等)需要查阅InputStreamReader。
目前为了解决当前问题,不需要,只需要使用默认即可。
使用FileReader时,了解它的功能,看它所属的体系顶层。Reader。
Reader:读取字符流的抽象超类。read():读取单个字符并返回, read(char[]):将数据读取到数组中,并返回读取的个数。
FileReader : 字节读取流+默认编码表。
字符流:为了便于操作数据中的字符数据。原理: 字节流+编码表。
字符流的两个基类。
Reader:read()读取字符。
|-
Writer(Reader的另请参见):写入字符。
|-
字节流操作的是字节数组;字符流操作的是字符数组。