打开一个文本文件,另存为:
Ansi就是系统默认编码(就是gbk)
建一个编码是utf-8的txt文件,
例:
import java.io.FileWriter; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { //确定目的地 FileWriter fw=new FileWriter("E:\zyx\java\utf-8.txt",true); //写入目的地 fw.write("你好"); //释放资源 fw.close(); } }
所以字符流无法实现utf-8编码格式文件的读和写。
如果需要指定编码和缓冲区大小时,可以在字节流的基础上,构造一个InputStreamReader或者OutputStreamWriter。
1 OutputStreamWriter类
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节。它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。
1.1继承体系
1.2原理
在OutputStreamWriter流中维护自己的缓冲区,当调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。然后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。
1.3构造方法
只支持utf-8和gbk这两个码表
OutputStreamWriter是一个字符流,所以字符流的方法都能用
例:
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class Demo02 { public static void main(String[] args) throws IOException { //指定目的地 FileOutputStream fos=new FileOutputStream("E:\zyx\java\utf-8.txt",true); //续写 //创建转换流 OutputStreamWriter osw=new OutputStreamWriter(fos,"utf-8"); //写入 osw.write("你好你好"); //刷新数据 osw.flush(); //释放资源:(new了谁关谁,先开的先关) osw.close(); fos.close(); } }
注意:释放资源时,new了谁关谁,先开的后关
gbk例子:
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class Demo03 { public static void main(String[] args) throws IOException { //指定目的地 FileOutputStream fos=new FileOutputStream("E:\zyx\java\gbk.txt",true); //续写 //创建转换流 OutputStreamWriter osw=new OutputStreamWriter(fos,"gbk"); //写入 osw.write("你好,java"); //osw.flush(); //释放资源 osw.close(); fos.close(); } }
注意:gbk和utf-8不区分大小写,可以写成GBK
2 InputStreamReader类
utf-8是三个字节代表一个汉字,直接用Filereader不能读
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
2.1继承体系
2.2构造方法
例:
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class Demo04 { public static void main(String[] args) throws IOException { //获取数据源 FileInputStream fis=new FileInputStream("E:\zyx\java\utf-8.txt"); //创建转换流 InputStreamReader isr=new InputStreamReader(fis,"utf-8"); //开始读取 int len=0; while((len=isr.read())!=-1){ System.out.print((char)len); } //释放资源 isr.close(); fis.close(); } }
改成gbk是这样:
用字符数组读gbk的文件
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class Demo05 { public static void main(String[] args) throws IOException { FileInputStream fis=new FileInputStream("E:\zyx\java\gbk.txt"); InputStreamReader isr=new InputStreamReader(fis); char[] ch=new char[24]; int len=0; while((len=isr.read(ch))!=-1){ System.out.print(new String(ch,0,len)); } isr.close(); fis.close(); } }
3 转换流和子类区别
发现有如下继承关系:
OutputStreamWriter:
|--FileWriter:
InputStreamReader:
|--FileReader;
父类和子类的功能的区别:
1)OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。字符转换流原理:字节流+编码表。
2)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");
这三句代码的功能是一样的,其中第三句最为便捷。
3)一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。
4)用子类的条件:
1、操作的是文件。2、使用默认编码。
总结:
字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader
字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter
4缓冲流
读取数据量大的文件时,读取的速度会很慢,很影响程序的效率。
Java中提高了一套缓冲流,它的存在,可提高IO流的读写速度。
缓冲流,根据流的分类分类字节缓冲流与字符缓冲流。
4.1字节缓冲流
字节缓冲流根据流的方向,共有2个
写入数据到流中,字节缓冲输出流 BufferedOutputStream
读取流中的数据,字节缓冲输入流 BufferedInputStream
它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度
缓冲区就是一个容器
4.1.1构造方法
例:
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo06 { public static void main(String[] args) throws IOException { method02(); } //字节输出缓冲流 public static void method01() throws IOException{ //明确目的地 FileOutputStream fos=new FileOutputStream("E:\zyx\java\demo.txt"); //加缓冲流 BufferedOutputStream bos=new BufferedOutputStream(fos); bos.write(100); bos.close(); //fos.close(); //可以不加,bos会自动关上fos } //字节输入缓冲流 public static void method02() throws IOException{ //明确数据源 FileInputStream fis=new FileInputStream("E:\zyx\java\demo.txt"); //加缓冲流 BufferedInputStream bis=new BufferedInputStream(fis); int len=0; while((len=bis.read())!=-1){ System.out.println((char)len); } bis.close(); } }
4.1.2复制比较示例
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; public class Demo07 { public static void main(String[] args) throws IOException { copy02(); } //单个字节文件复制 public static void copy01() throws IOException{ //明确数据源 FileInputStream fis=new FileInputStream("E:\zyx\java\tomcat.zip"); //明确目的地 FileOutputStream fos=new FileOutputStream("E:\zyx\java\a\tomcat.zip"); //开始复制 long time1=System.currentTimeMillis(); int len=0; while((len=fis.read())!=-1){ fos.write(len); } long time2=System.currentTimeMillis(); System.out.println(time2-time1); fis.close(); fos.close(); } //单个字节,字节缓冲流复制 public static void copy02() throws IOException{ //明确数据源 FileInputStream fis=new FileInputStream("E:\zyx\java\tomcat.zip"); BufferedInputStream bis=new BufferedInputStream(fis); //明确目的地 FileOutputStream fos=new FileOutputStream("E:\zyx\java\a\tomcat.zip"); BufferedOutputStream bos=new BufferedOutputStream(fos); //开始复制 long time1=System.currentTimeMillis(); int len=0; while((len=bis.read())!=-1){ bos.write(len); } long time2=System.currentTimeMillis(); System.out.println(time2-time1); bis.close(); bos.close(); //System.out.println(system.in); } }
copy01()结果:
copy02()结果:
4.1.3用字节数组方式复制的比较
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class CopyTest { public static void main(String[] args) throws IOException { copy01(); } //普通流复制 public static void copy01() throws IOException{ //指定数据源 FileInputStream fis=new FileInputStream("E:\zyx\java\eclipse.zip"); //指定目的地 FileOutputStream fos=new FileOutputStream("E:\zyx\java\e\eclipse.zip"); //复制 long start=System.currentTimeMillis(); int len=0; byte[] bys=new byte[1024]; while((len=fis.read(bys))!=-1){ fos.write(bys); } long end=System.currentTimeMillis(); System.out.println(end-start); fis.close(); fos.close(); } //缓冲流复制 public static void copy02() throws IOException{ //指定数据源 FileInputStream fis=new FileInputStream("E:\zyx\java\eclipse.zip"); BufferedInputStream bis=new BufferedInputStream(fis); //指定目的地 FileOutputStream fos=new FileOutputStream("E:\zyx\java\f\eclipse.zip"); BufferedOutputStream bos=new BufferedOutputStream(fos); long start=System.currentTimeMillis(); int len=0; byte[] bys=new byte[1024]; while((len=bis.read(bys))!=-1){ bos.write(bys); } long end=System.currentTimeMillis(); System.out.println(end-start); bis.close(); bos.close(); } }
结果比较:
5字符缓冲流
字符缓冲输入流 BufferedReader
字符缓冲输出流 BufferedWriter
完成文本数据的高效的写入与读取的操作
5.1 BufferedWriter
换行:
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { //明确日的地 FileWriter fw=new FileWriter("E:\zyx\java\demo01.txt"); //添加缓冲流 BufferedWriter bw=new BufferedWriter(fw); //会自动关闭fw //写入文件 bw.write("你好 "); bw.flush(); fw.write("java "); bw.flush(); bw.write("中国 "); bw.close(); //会自动关闭fw } }
newLine() 方法:
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { //明确日的地 FileWriter fw=new FileWriter("E:\zyx\java\demo01.txt"); //添加缓冲流 BufferedWriter bw=new BufferedWriter(fw); //会自动关闭fw //写入文件 bw.write("你好"); bw.newLine(); bw.flush(); fw.write("java"); bw.newLine(); bw.flush(); bw.write("中国"); bw.newLine(); bw.close(); //会自动关闭fw } }
Tips:
是windows的换行
Linux是
5.2字符缓冲输入流 BufferedReader
方法public String readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null
例:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { // 明确数据源 FileReader fr = new FileReader("E:\zyx\java\demo01.txt"); // 添加缓冲流 BufferedReader br = new BufferedReader(fr); // 读取 String line = ""; int lineNum = 0; // 加个行号 while ((line = br.readLine()) != null) { lineNum++; System.out.println(lineNum + " " + line); } fr.close(); } }
Tips:
readLine()不会把换行符读出来
可以手动加一个行号
5.3复制文本文件比较
6流的操作规律
IO流中对象很多,解决问题(处理设备上的数据时)到底该用哪个对象呢?
把IO流进行了规律的总结(四个明确):
明确一:要操作的数据是数据源还是数据目的。
源:InputStream Reader
目的:OutputStream Writer
先根据需求明确要读,还是要写。
明确二:要操作的数据是字节还是文本呢?
源:
字节:InputStream
文本:Reader
目的:
字节:OutputStream
文本:Writer
已经明确到了具体的体系上。
明确三:明确数据所在的具体设备。
源设备:
硬盘:文件 File开头。
内存:数组,字符串。
键盘:System.in;
网络:Socket
目的设备:
硬盘:文件 File开头。
内存:数组,字符串。
屏幕:System.out
网络:Socket
完全可以明确具体要使用哪个流对象。
明确四:是否需要额外功能呢?
额外功能:
转换吗?转换流。InputStreamReader OutputStreamWriter
高效吗?缓冲区对象。BufferedXXX
InputStream
FileInputStream
BufferedInputStream
OuputStream
FileOutputStream
BufferedOuputStream
Writer
OutputStreamWriter
FileWriter
BufferedWriter
Reader
InputStreamReader
FileReader
BufferedReader