Java基础系列35-IO流

x33g5p2x  于2021-12-18 转载在 其他  
字(31.7k)|赞(0)|评价(0)|浏览(496)

一.IO流概述

什么是IO流,其作用为?

  1. I ------ Input --> 输入 --> 读取
  2. O — Output --> 输出 --> 写出

常见应用:

  1. 文件复制
  2. 文件上传
  3. 文件下载

IO流的分类汇总:

  1. 字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码
  2. 字节缓冲区流 (字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码)
  3. 转换流 (字符流) = 字节流 + 编码表
  4. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
  5. 字符缓冲区流
  • 字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
    a1 InputStream 字节流输入超类
      a1.1 FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
      
  1. //指定输入流
  2. //FileInputStream fis = new FileInputStream(new File("fis.txt"));//效果同下行代码
  3. FileInputStream fis = new FileInputStream("fis.txt");
  4. //a.一次读取一个字符
  5. int by;
  6. //如果fis.read不等于-1说明还有数据,则继续读文件
  7. while ((by = fis.read()) != -1) {
  8. System.out.print((char) by);//打印结果
  9. }
  10. //b.一次读取一个字符数组
  11. byte[] bys = new byte[1024];//每次读取最大bys长度个字节存入数组,长度建议1024或1024的整数倍
  12. int len;//代表有效个数
  13. //将数据读取到数组中, 并用len记录读取到的有效字节个数
  14. //fis.read(bys)=>读取一次bys长度内容写入bys(每次覆盖之前内容),如果剩余文件内容不足以写满bys,(长度1024,剩余1000字节)则bys中最后字节(24字节)保持上一次写入的内容 => 所以每次要截取new String(bys,0,len),避免读到上一次剩余的内容
  15. while ((len = fis.read(bys)) != -1) {
  16. System.out.print(new String(bys, 0, len));//打印结果
  17. }
  18. //释放资源
  19. fis.close();

b1 字节缓冲区流  BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码

  1. //字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流
  2. //Q:为什么字节缓冲流的构造方法需要传入一个In/OutputStream
  3. //A:字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作。
  4. //指定输入流
  5. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("name.txt"));
  6. //a.一次读取一个字符(不能读取中文,中文一般2-4字节,一个一个字节读会乱码)
  7. int by;
  8. while ((by = bis.read()) != -1) {
  9. System.out.print((char) by);
  10. }
  11. //b.一次读取一个字符数组
  12. byte[] bys = new byte[1024];
  13. int len;
  14. while ((len = bis.read(bys)) != -1) {
  15. System.out.print(new String(bys, 0, len));
  16. }
  17. //释放资源
  18. bis.close();

a2 OutPutStream 字节流输出超类
  a2.1 FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码

  1. //指定输出流
  2. //FileOutputStream fos = new FileOutputStream(new File("fos.txt"));//效果同下行代码
  3. //FileOutputStream fos = new FileOutputStream("fos.txt" , false);//false表示不追加文件->每次写入覆盖之前的内容
  4. FileOutputStream fos = new FileOutputStream("fos.txt");
  5. FileInputStream fis = new FileInputStream("fis.txt");
  6. //a.一次写入一个字符(不能读取中文,中文一般2-4字节,一个一个字节读会乱码)
  7. int by;
  8. while ((by = fis.read()) != -1) {
  9. System.out.print((char) by);//打印结果
  10. }
  11. //b.一次写入一个字符数组
  12. byte[] bytes = new byte[1024];
  13. int len;
  14. while ((len = fis.read(bytes)) != -1) {
  15. fos.write(bytes, 0, len);
  16. }
  17. //释放资源
  18. fos.close();
  19. fis.close();

b2 字节缓冲区流  BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码

  1. //字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流
  2. //Q:为什么字节缓冲流的构造方法需要传入一个In/OutputStream
  3. //A:字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作。
  4. //指定输入流
  5. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
  6. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
  7. //a.一次读取一个字符
  8. int by;
  9. while ((by = bis.read()) != -1) {
  10. bos.write(by);//写入字符串
  11. bos.flush();//刷新该流的缓冲,写入文件
  12. }
  13. //b.一次读取一个字符数组
  14. byte[] bytes = new byte[1024];
  15. int len;
  16. while ((len = bis.read(bytes)) != -1) {
  17. System.out.println(new String(bytes,0,len));
  18. bos.write(bytes,0,len);//写入字符串
  19. bos.flush();//刷新该流的缓冲,写入文件
  20. }
  21. //释放资源
  22. bis.close();
  23. bos.close();
  • c 转换流 (字符流) = 字节流 + 编码表
  1. //指定编码为UTF-8的字符输出流
  2. OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("source.txt"),"UTF-8");
  3. //指定编码为UTF-8的字符输入流
  4. InputStreamReader isr = new InputStreamReader(new FileInputStream("target.txt"),"UTF-8");
  5. /*
  6. 常见的编码表:
  7. ASCII : 美国标准信息交换码, 用一个字节的7位表示数据
  8. ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII
  9. GB2312 : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII
  10. UTF-8 : 是一种可变长度的字符编码, 用1-3个字节表示数据, 又称为万国码, 兼容ASCII用在网页上可以
  11. 统一页面中的中文简体繁体和其他语言的显示.
  12. */
  • d字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
    d1 Reader 字符流输入超类
      d1.1 InputStreamReader 用 默认/指定 编码读数据
  1. //指定输入流 目标文件和字符集 ,如果不指定字符集则按照默认编码表 (java7=GBK,java8=UTF-8)
  2. InputStreamReader isr = new InputStreamReader(new FileInputStream(""),"GBK");

d1.1.1 FileReader ↓作为BufferedReader构造器的参数使用↓

  1. //转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流InputStreamReader提供了对应的子类InputStreamReader
  2. /*
  3. (子类)FileWriter:用来写入字符文件的便捷类
  4. (父类)OutputStreamWriter: FileWriter + 默认编码表(java7=GBK,java8=UTF-8)
  5. (子类)FileReader:用来读取字符文件的便捷类
  6. (父类)InputStreamReader: FileReader + 默认编码表(java7=GBK,java8=UTF-8)
  7. */
  8. //封装数据源
  9. FileReader fr = new FileReader("source.txt");
  10. //封装目的地
  11. FileWriter fw = new FileWriter("target.txt");

e1 字符缓冲区流  BufferedReader 最常用

  1. //指定输入流
  2. BufferedReader br = new BufferedReader(new FileReader("source.txt"));
  3. //指定输出流
  4. BufferedWriter bw = new BufferedWriter(new FileWriter("target.txt"));
  5. //a.一次读取一个字符
  6. int ch;
  7. while ((ch = br.read()) != -1) {
  8. //对应Unicode编码10进制的值 查询工具 =>
  9. //http://www.mytju.com/classcode/tools/encode_gb2312.asp
  10. System.out.println(ch);
  11. }
  12. //b.一次读取多个字符【注意 换行符也算字符】
  13. char[] bytes = new char[1024];//一次取出1024个字符
  14. int len;//代表有效个数
  15. while((len = br.read(bytes)) != -1)
  16. {
  17. System.out.print(new String(chars, 0, len));//注意是print不是println
  18. }
  19. //c.读取一整行字符串【注意 不包括换行符,需要手动newLine()换行】
  20. //String line = br.readLine();
  21. String line;//代表一整行字符串
  22. //按行读取整篇文章的内容
  23. while((line = br.readLine()) != null)
  24. {
  25. System.out.println(line);
  26. }
  27. //释放资源
  28. br.close();
  29. bw.close();

d2 Writer 字符流输出超类
   d2.1 PrintWriter
   d2.2 OutputStreamWriter 用 默认/指定 编码写数据

  1. //指定输出流 目标文件和字符集,如果不指定字符集则按照默认编码表 (java7=GBK,java8=UTF-8)
  2. OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("target.txt"),"GBK");

d2.2.1 FileWriter ↓作为BufferedWriter构造器的参数使用↓

  1. //转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流OutputStreamWriter提供了对应的子类FileWriter
  2. /*
  3. (子类)FileWriter:用来写入字符文件的便捷类
  4. (父类)OutputStreamWriter: FileWriter + 默认编码表(java7=GBK,java8=UTF-8)
  5. (子类)FileReader:用来读取字符文件的便捷类
  6. (父类)InputStreamReader: FileReader + 默认编码表(java7=GBK,java8=UTF-8)
  7. */
  8. //封装数据源
  9. FileReader fr = new FileReader("source.txt");
  10. //封装目的地
  11. FileWriter fw = new FileWriter("target.txt");

e2 字符缓冲区流 BufferedWriter 最常用

  1. //指定输入流
  2. BufferedReader br = new BufferedReader(new FileReader("br.txt"));
  3. //指定输出流
  4. BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
  5. //a.一次读取一个字符
  6. int ch;
  7. while ((ch = br.read()) != -1) {
  8. bw.write(ch);//写入字符串
  9. bw.flush();//刷新该流的缓冲,写入文件
  10. }
  11. //b.一次读取多个字符【注意 换行符也算字符】
  12. char[] bytes = new char[1024];//一次取出1024个字符
  13. int len;//代表有效个数
  14. while((len = br.read(bytes)) != -1)
  15. {
  16. bw.write(new String(bytes, 0 , len));//写入字符串
  17. bw.newLine();
  18. bw.flush();//刷新该流的缓冲,写入文件
  19. }
  20. //c.读取一整行字符串【注意 不包括换行符,需要手动newLine()换行】
  21. //String line = br.readLine();
  22. String line;//代表一整行字符串
  23. //按行读取整篇文章的内容
  24. while((line = br.readLine()) != null)
  25. {
  26. bw.write(line);//写入字符串
  27. bw.newLine();
  28. bw.flush();//刷新该流的缓冲,写入文件
  29. }
  30. //释放资源
  31. br.close();
  32. bw.close();

二. 字节流

a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
 InputStream 字节流输入超类
 FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
  b. 字节缓冲区流  BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
 OutPutStream 字节流输出超类
  FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
   b 字节缓冲区流  BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码

2.1 FOS与FIS

简写说明:

  • FIS = FileInPutStream
  • FOS = FileOutPutStream

字节流写数据:

  • OutputStream:此抽象类是表示输出字节流的所有类的超类
  • FileOutputStream:文件输出流是用于将数据写入 File

字符流读数据:

  • OutputStream:此抽象类是表示输出字节流的所有类的超类
  • FileOutputStream:文件输出流是用于将数据写入 File

构造方法:

  1. //创建一个向具有指定名称的文件中写入数据的输出文件流。
  2. FileOutputStream(String name)

字节流写数据的步骤:

  1. 创建字节输出流对象
  2. 调用写数据的方法 write(int);
  3. 释放资源 close()

代码:

  1. package Java_study;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. /**
  5. *
  6. * @author 只是甲
  7. * @date 2021-07-19
  8. * @remark 字节流FileOutputStream写出数据
  9. *
  10. */
  11. public class io1 {
  12. public static void main(String[] args) throws IOException {
  13. //创建直接输出流对象 throws FileNotFoundException
  14. FileOutputStream fos = new FileOutputStream("a.txt");
  15. //throws IOException (包含FileNotFoundException)
  16. System.out.println("fos.write");
  17. fos.write(65);//A
  18. fos.write(66);//B
  19. System.out.println("写入结束");
  20. //关闭IO流,回收系统资源
  21. fos.close();
  22. }
  23. }

2.2 FOS写数据的三种方式

方法摘要:

  1. //a.写出数据的三个方法
  2. //一次写一个字节
  3. public void write(int b)
  4. //一次写一个字节数组
  5. public void write(byte[] b)
  6. //一次写一个字节数组的一部分
  7. public void write(byte[] b,int off,int len)
  8. //b.String类中的方法
  9. //将字符串转换为字节数组
  10. byte[] getBytes()

代码:

  1. package Java_study;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. /**
  6. *
  7. * @author 只是甲
  8. * @date 2021-07-19
  9. * @remark 字节流FileOutputStream写数据的三种方式
  10. * A.构造方法的三种方式:
  11. * 1. FileOutputStream(String name)
  12. * 2. FileOutPutStream(File file)
  13. * 3. FileOutPutStream(new File(xxx))
  14. * 4. FileOutputStream(xxx,true) //true=追加数据,默认为false,清空后重新写入数据
  15. *
  16. * B.写数据的三种方式: throws IOException
  17. * 1. FileOutputStream.write(int b):一次写一个字节
  18. * 2. FileOutputStream.write(byte[] b):一次写一个字节数组
  19. * 3. FileOutputStream.write(byte[] b,inf off,int len):一次写一个字节数组的一部分
  20. *
  21. * 字节流写数据的步骤:
  22. * a: 创建字节输出流对象 new FileOutPutStream(String name)
  23. * b: 调用写数据的方法
  24. * c: 释放资源 fos.close()
  25. *
  26. */
  27. public class io2 {
  28. public static void main(String[] args) throws IOException{
  29. //A1. FileOutputStream构造方式1 FileOutputStream(String name)
  30. FileOutputStream fos1 = new FileOutputStream("b.txt");
  31. //A2. FileOutputStream构造方式2 FileOutPutStream(File file)
  32. File f2 = new File("c.txt");
  33. FileOutputStream fos2 = new FileOutputStream(f2);
  34. //A3. FileOutPutStream构造方式3 FileOutPutStream(new File(xxx))
  35. FileOutputStream fos3 = new FileOutputStream(new File("d.txt"));
  36. //B1. 写入数据方式1 FileOutputStream.write(int b):一次写一个字节
  37. //throws IOException
  38. fos1.write(65);
  39. //B2. 写入数据方式2 FileOutputStream.write(byte[] b):一次写一个字节数组
  40. byte[] bys = {65, 66, 67, 68, 69};
  41. fos2.write(bys);
  42. //B3. 写入数据方式3 FileOutputStream.write(byte[] b,inf off,int len):一次写一个字节数组的一部分
  43. fos3.write("ABCDE".getBytes(), 0, 3);
  44. File path = new File("");
  45. System.out.println("文件路径:" + path.getAbsolutePath());
  46. //释放资源
  47. fos1.close();
  48. fos2.close();
  49. fos3.close();
  50. }
  51. }

2.3 FOS如何实现换行和追加写数据

FIS = FileInPutStream

不同的操作系统,针对换行的符号识别是不一样的:

  • windows:\r\n
  • linux:\n
  • mac:\r

如何实现数据的追加写入?

  • 用构造方法带第二个参数是true的情况即可

代码:

  1. package Java_study;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. /**
  6. *
  7. * @author 只是甲
  8. * @date 2021-07-19
  9. * @remark 字节流FileOutputStream写数据换行、追加
  10. *
  11. */
  12. public class io3 {
  13. public static void main(String[] args) throws IOException{
  14. //先清空文件
  15. FileOutputStream clear = new FileOutputStream("b.txt");
  16. clear.write("".getBytes());
  17. //如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处(默认为false)
  18. FileOutputStream fos = new FileOutputStream("b.txt", true);
  19. //玄幻写入三次hello和换行
  20. for (int i = 0; i < 3; i++) {
  21. fos.write("hello".getBytes());
  22. fos.write("\r\n".getBytes());
  23. }
  24. System.out.println("文件路径为:" + new File("").getAbsolutePath());
  25. //释放资源
  26. fos.close();
  27. }
  28. }

2.4 FOS写数据加入异常处理

FIS = FileInPutStream

try…catch.finally

  1. //格式
  2. try{
  3. 可能发生问题的代码
  4. }catch(){
  5. 处理异常代码
  6. }finally{
  7. 一定会被执行的代码. // 通常用于释放资源, 做善后的动作
  8. }

代码:

  1. package Java_study;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. /**
  5. *
  6. * @author 只是甲
  7. * @date 2021-07-19
  8. * @remark 字节流FileOutputStream写数据加入异常处理
  9. *
  10. */
  11. public class io4 {
  12. public static void main(String[] args) {
  13. //fos放在外面是为了在finally中可以关闭
  14. FileOutputStream fos = null;
  15. try {
  16. fos = new FileOutputStream("d.txt");
  17. fos.write("hello".getBytes());
  18. } catch (IOException e) {
  19. e.printStackTrace();
  20. } finally {
  21. if (fos != null) {
  22. //释放资源
  23. try {
  24. fos.close();
  25. } catch (IOException e) {
  26. System.out.println("fos关闭失败");
  27. }
  28. }
  29. }
  30. }
  31. }

2.5 FIS读数据方式1一次读取一个字节

FIS = FileInPutStream

字节流读数据的步骤:

  • A : 创建字节输入流对象
  • B : 调用读数据的方法
  • C : 释放资源

代码:

  1. package Java_study;
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. /**
  5. *
  6. * @author 只是甲
  7. * @remark 字节流FileInputStream读数据方式1
  8. *
  9. */
  10. public class io5 {
  11. public static void main(String[] args) throws IOException {
  12. System.out.println("读取数据方式1: 一次读取一个字节");
  13. //创建字节输入流对象
  14. FileInputStream fis1 = new FileInputStream("b.txt");//刚才在b.txt写入了3行hello
  15. for (int i = 0; i < 20; i++) {
  16. System.out.println(fis1.read());
  17. }
  18. System.out.println("改进为循环方式打印");
  19. FileInputStream fis2 = new FileInputStream("b.txt");//刚才在b.txt写入了3行helloWorld
  20. int by;
  21. //如果fis.read不等于-1说明还有数据,则继续读文件
  22. while ((by = fis2.read()) != -1) {
  23. System.out.println((char) by);
  24. }
  25. }
  26. }

测试记录:

  1. 读取数据方式1: 一次读取一个字节
  2. 104
  3. 101
  4. 108
  5. 108
  6. 111
  7. 13
  8. 10
  9. 104
  10. 101
  11. 108
  12. 108
  13. 111
  14. 13
  15. 10
  16. 104
  17. 101
  18. 108
  19. 108
  20. 111
  21. 13
  22. 改进为循环方式打印
  23. h
  24. e
  25. l
  26. l
  27. o
  28. h
  29. e
  30. l
  31. l
  32. o
  33. h
  34. e
  35. l
  36. l
  37. o

2.6 FIS读数据方式2一次读取一个字节数组

方法摘要:

  1. /*从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中
  2. 返回值是读入缓冲区的字节总数,也就是实际的读取个数
  3. 如果因为已经到达文件末尾而没有更多的数据,则返回 -1。*/
  4. public int read(byte[] b):

代码:

  1. package Java_study;
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. /**
  5. *
  6. * @author 只是甲
  7. * @remark FileInputStream读数据方式2
  8. *
  9. */
  10. public class io6 {
  11. public static void main(String[] args) throws IOException{
  12. System.out.println("----读取数据方式2: 一次读取一个直接数组-----");
  13. FileInputStream fis1 = new FileInputStream("b.txt");//刚才在b.txt写入了3行hello
  14. //标准代码字符缓冲区bys1长度应为1024或1024的整数倍,这里先用8演示读取的原理
  15. byte[] bys1 = new byte[8];
  16. //第一次读取
  17. int len1 = fis1.read(bys1);
  18. System.out.println(len1);//8
  19. System.out.println("第一次读取: " + new String(bys1));
  20. //第二次读取
  21. len1 = fis1.read(bys1);
  22. System.out.println(len1);//8
  23. /*
  24. 第二次读取: ello
  25. he
  26. */
  27. System.out.println("第二次读取: " + new String(bys1));
  28. // 第三次读取
  29. len1 = fis1.read(bys1);
  30. System.out.println(len1);//5 => 只读取了5个字符,就返回了5
  31. /*
  32. 第三次读取: llo
  33. he
  34. */
  35. /* 解析:
  36. 文件内容为
  37. hello\r\n
  38. hello\r\n
  39. hello\r\n
  40. 第一次读取8个字节为 [h] [e] [l] [l] [o] [\r][\n] [h]
  41. 第二次读取8个字节为 [e] [l] [l] [o] [\r][\n] [h] [e]
  42. 第三次读取8个字节为 [l] [l] [o] [\r][\n]
  43. 但数组写入方式是每次覆盖前一次的,所以第二次写入的还保留着
  44. bys[5] = \r
  45. bys[6] = h
  46. bys[7] = e
  47. 所以第三次数组内容为 [l] [l] [o] [\r][\n][\n] [h] [e]
  48. 所以才会打印出以上内容
  49. */
  50. System.out.println("第三次读取: " + new String(bys1));
  51. //第四次读取
  52. len1 = fis1.read(bys1);
  53. System.out.println(len1);//-1 => 表示没有数据了
  54. System.out.println("-----改进为循环读取文件-----");
  55. //创建字节流输入对象
  56. FileInputStream fis2 = new FileInputStream("b.txt");
  57. byte[] bys2 = new byte[1024];//1024或者1024的整数倍
  58. int len2;
  59. //将数据读取到数组中, 并用len记录读取到的有效字节个数
  60. while ((len2 = fis2.read(bys2)) != -1 ) {
  61. //只读取到len的长度,否则会出现
  62. System.out.print(new String(bys2, 0, len2));
  63. }
  64. System.out.println("\r\n读取结束");
  65. fis2.close();
  66. }
  67. }

测试记录:

  1. ----读取数据方式2: 一次读取一个直接数组-----
  2. 8
  3. 第一次读取: hello
  4. h
  5. 8
  6. 第二次读取: ello
  7. he
  8. 5
  9. 第三次读取: llo
  10. he
  11. -1
  12. -----改进为循环读取文件-----
  13. hello
  14. hello
  15. hello
  16. 读取结束

2.7 字节流练习之复制文本文件

需求:

  • 拷贝文本文件

分析:

  • 第一步: 创建输入输出流对象关联数据源和数据目的
  • 第二步: 定义字节数组,为了提高效率
  • 第三步: 将数据通过while循环不断读取到字节数组中
  • 第四步: 将数据从字节数组中取出并写出
  • 第五步: 释放资源

待拷贝的文本文件(d:\窗里窗外.txt):

  1. 《窗里窗外》是林青霞近5年所写的46篇散文的结集,虽是旧作,但该书记录她19岁以《窗外》成名后多方面的人生经历,字字真实深刻。《窗里窗外》共分为六个章节:“戏”里说的是她的出道故事、拍戏的甘苦、对于作品的内心话;“亲”谈她的家人亲情;“友”则书写她与挚友的交往,细谈她与三毛、黄霑、张国荣、龙应台、琼瑶、徐克等人的往来互动;“趣”是她的生活记趣,有旅行见闻,也有她与影迷的邂逅;“缘”则书写她一生难忘的相遇,像是和记者的友谊,和季羡林的会面之缘;“悟”里记录了她对人生的体悟和感动,以及她向圣严法师求道的故事。此外,书中还完整收录了林青霞一些未公开的照片。
  2. 1节:人生小语(1)…

代码:

  1. package Java_study;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. /**
  7. *
  8. * @author 只是甲
  9. * @remark 直接流复习之复制文本文件
  10. *
  11. */
  12. public class io7 {
  13. public static void main(String[] args) throws IOException{
  14. //封装数据源
  15. FileInputStream fis = new FileInputStream("d:" + File.separator + "窗里窗外.txt");
  16. //封装目的地(目标文件,追加true清空重写false)
  17. FileOutputStream fos = new FileOutputStream("d:" + File.separator + "杜兰特.txt", false);
  18. //a.一次写入一个字符
  19. int by;
  20. while ((by = fis.read()) != -1 ) {
  21. fos.write(by);
  22. }
  23. //b.一次写入一个字符数组
  24. byte[] bys = new byte[1024];
  25. int len;
  26. while ((len = fis.read(bys)) != -1 ) {
  27. fos.write(bys, 0, len);
  28. }
  29. //释放资源
  30. fos.close();
  31. fis.close();
  32. }
  33. }

2.8 字节流练习之复制图片

思路:

  • 同理2.7案例

代码:

  1. package Java_study;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. /**
  7. *
  8. * @author 只是甲
  9. * @date 2021-07-20
  10. * @remark 直接流复习之复制文本文件
  11. *
  12. */
  13. public class io8 {
  14. public static void main(String[] args) throws IOException{
  15. //封装数据源
  16. FileInputStream fis1 = new FileInputStream("d:" + File.separator + "字节流.bmp");
  17. FileInputStream fis2 = new FileInputStream("d:" + File.separator + "字节流.bmp");
  18. //封装目的地
  19. FileOutputStream fos1 = new FileOutputStream("d:" + File.separator + "copy1.bmp");
  20. FileOutputStream fos2 = new FileOutputStream("d:" + File.separator + "copy2.bmp");
  21. //读取数据
  22. int by;
  23. //方式1: 一次读取一个直接
  24. //如果fis.read不等于-1说明还有数据,则继续读文件
  25. while ((by = fis1.read()) != -1 ) {
  26. fos1.write(by);
  27. }
  28. //方式2: 一次读取一个字节数组
  29. byte[] bys = new byte[1024];
  30. int len;
  31. while ((len = fis2.read(bys)) != -1) {
  32. fos2.write(bys, 0, len);
  33. }
  34. //释放资源
  35. fis1.close();
  36. fis2.close();
  37. fos1.close();
  38. fos2.close();
  39. }
  40. }

三. 字节缓冲区流

a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)

  • InputStream 字节流输入超类
  • FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
      b. 字节缓冲区流  BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
  • OutPutStream 字节流输出超类
      FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
        b 字节缓冲区流  BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码

3.1 概述

作用:

  • 字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果
  • java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流

字节缓冲流:

  • BufferedOutputStream : 字节缓冲输出流
  • BufferedInputStream : 字节缓冲输入流

为什么字节缓冲流的构造方法需要传入一个OutputStream:

  • 字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. *
  5. * @author 只是甲
  6. * @date 2021-07-20
  7. * @remark 字节缓冲流
  8. *
  9. */
  10. public class io9 {
  11. public static void main(String[] args) throws IOException{
  12. //指定字符缓冲输出流
  13. // FileOutputStream fos = new FileOutputStream("a.txt");
  14. // BufferedOutputStream bos = new BufferedOutputStream(fos);
  15. // 上面的两句等价于下面的这一句
  16. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
  17. byte[] bytes = "hello".getBytes();
  18. bos.write(bytes);
  19. bos.close();
  20. //指定字符缓冲输入流
  21. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
  22. //方式1: 一次读取一个字节
  23. int by;
  24. while ((by = bis.read()) != -1) {
  25. System.out.println((char) (by));
  26. }
  27. //方式2: 一次读取一个直接数组
  28. byte[] bys = new byte[1024];
  29. int len;
  30. while ((len = bis.read(bys)) != -1) {
  31. System.out.println(new String(bys, 0, len));
  32. }
  33. //释放资源
  34. bos.close();
  35. bis.close();
  36. }
  37. }

3.2 四种方式复制图片效率测试

方法摘要:

  1. //返回以毫秒为单位的当前时间。
  2. public static long currentTimeMillis()

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. * @author GroupiesM
  5. * @date 2021/04/27
  6. * @introduction 字节流&字节缓冲区流四种方式复制AVI并测试效率
  7. *
  8. * 源文件: d:\\复制视频.avi
  9. * 大小: 34904KB
  10. *
  11. * method1: 基本字节流,一次读取一个字节 => method1.avi => 198001毫秒
  12. * method2: 基本字节流,一次读写一个字节数组 => method2.avi => 278毫秒
  13. * method3: 缓冲字节流,一次读取一个字节 => method3.avi => 384毫秒
  14. * method4: 缓冲字节流,一次读写一个字节数组 => method4.avi => 190毫秒
  15. *
  16. * 结论: method4 > method2 > method3 > method1
  17. */
  18. public class io10 {
  19. public static void main(String[] args) throws IOException {
  20. //记录method1时间
  21. long start1 = System.currentTimeMillis();
  22. method1();//method1共耗时198001毫秒
  23. long end1 = System.currentTimeMillis();
  24. System.out.println("method1共耗时" + (end1 - start1) + "毫秒");
  25. //记录method2时间
  26. long start2 = System.currentTimeMillis();
  27. method2();//method2共耗时278毫秒
  28. long end2 = System.currentTimeMillis();
  29. System.out.println("method2共耗时" + (end2 - start2) + "毫秒");
  30. //记录method3时间
  31. long start3 = System.currentTimeMillis();
  32. method3();//method3共耗时384毫秒
  33. long end3 = System.currentTimeMillis();
  34. System.out.println("method3共耗时" + (end3 - start3) + "毫秒");
  35. //记录method4时间
  36. long start4 = System.currentTimeMillis();
  37. method4();//method4共耗时190毫秒
  38. long end4 = System.currentTimeMillis();
  39. System.out.println("method4共耗时" + (end4 - start4) + "毫秒");
  40. }
  41. //method1: 基本字节流,一次读取一个字节 => method1.avi
  42. private static void method1() throws IOException {
  43. //封装数据源
  44. FileInputStream fis = new FileInputStream("d:\\复制视频.avi");
  45. //封装目的地
  46. FileOutputStream fos = new FileOutputStream("d:\\method1.avi");
  47. int by;
  48. while ((by = fis.read()) != -1) {
  49. fos.write(by);
  50. }
  51. //释放资源
  52. fis.close();
  53. fos.close();
  54. }
  55. //method2: 基本字节流,一次读写一个字节数组 => method2.avi
  56. private static void method2() throws IOException {
  57. //封装数据源
  58. FileInputStream fis = new FileInputStream("d:\\复制视频.avi");
  59. //封装目的地
  60. FileOutputStream fos = new FileOutputStream("d:\\method2.avi");
  61. byte[] bys = new byte[1024];
  62. int len;
  63. while ((len = fis.read(bys)) != -1) {
  64. fos.write(bys, 0, len);
  65. }
  66. //释放资源
  67. fis.close();
  68. fos.close();
  69. }
  70. //method3: 缓冲字节流,一次读取一个字节 => method3.avi
  71. private static void method3() throws IOException {
  72. //封装数据源
  73. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制视频.avi"));
  74. //封装目的地
  75. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\method3.avi"));
  76. int by;
  77. while ((by = bis.read()) != -1) {
  78. bos.write(by);
  79. }
  80. //释放资源
  81. bis.close();
  82. bos.close();
  83. }
  84. //method4: 缓冲字节流,一次读写一个字节数组 => method4.avi
  85. private static void method4() throws IOException {
  86. //封装数据源
  87. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制视频.avi"));
  88. //封装目的地
  89. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\method4.avi"));
  90. byte[] bys = new byte[1024];
  91. int len;
  92. while ((len = bis.read(bys)) != -1) {
  93. bos.write(bys, 0, len);
  94. }
  95. //释放资源
  96. bis.close();
  97. bos.close();
  98. }
  99. }

四. 转换流

c. 转换流 (字符流) = 字节流 + 编码表

转换流出现的原因:

  • 由于字节流操作中文不是特别方便,所以,java就提供了转换流
  • 转换流 = 字节流 + 编码表

字节流读数据可能出现问题:

  • 字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。
  • 文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。
  • 汉字存储的规则
      左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。

代码:

  1. package Java_study;
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. import java.util.Arrays;
  5. /**
  6. * @author 只是甲
  7. * @date 2021-07-20
  8. * @remark 转换流出现的原因
  9. *
  10. */
  11. public class io11 {
  12. public static void main(String[] args) throws IOException{
  13. //基本字节流一次读取一个字节
  14. FileInputStream fis = new FileInputStream("a.txt");
  15. int by;
  16. while ((by = fis.read()) != -1 ) {
  17. System.out.print((char) by);
  18. }
  19. //释放资源,刷新缓冲区
  20. fis.close();
  21. System.out.println("");
  22. String s = "你";
  23. byte[] bys = s.getBytes("GBK");
  24. /*常见的编码表测试 中文"你"转换为字节数组
  25. UTF-8 => [-28, -67, -96] => JDK8中不指定编码则默认为 UTF-8
  26. GBK/GB2312 => [-60, -29] => JDK7中不指定编码则默认为 GBK/GB2312
  27. ISO-8859-1 => [63]
  28. ASCII => [63]
  29. UNICODE/UTF-16 => [-2, -1, 79, 96] => UNICODE 默认使用的是UTF-16的实现方式
  30. */
  31. System.out.println(Arrays.toString(bys));
  32. }
  33. }

测试记录:

  1. hi
  2. ????
  3. [-60, -29]

4.1 什么是编码表

编码表

  • 由字符及其对应的数据组成的一张表
  1. ASCII
  2. a 97
  3. A 65
  4. 0 48

常见的编码表:

  • ASCII : 美国标准信息交换码, 用一个字节的7位表示数据;(ASCII 0-126)
  • ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII;
  • GB2312/GBK : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII;
  • UTF-8 : 使用一到四个字节来编码一个码点。, 兼容ASCII;用在网页上可以统一页面中的中文简体繁体和其他语言的显示;
  • UNICODE : 为世界上所有字符都分配了一个唯一的数字编号,又称万国码;有多种实现方案(UTF-32 、UTF-16 、UTF-8)。

乱码问题:

  • 针对同一个数据, 采用的编码和解码不一致导致

代码:

  1. package Java_study;
  2. /**
  3. *
  4. * @author 只是甲
  5. * @date 2021-07-21
  6. * @remark 遍历编码表_int转char
  7. *
  8. */
  9. public class io12 {
  10. public static void main(String[] args) {
  11. int count = 0;
  12. for (int i = 8; i < 127; i++) {
  13. //每打印5个就换行一次
  14. if (count == 5) {
  15. System.out.println("");
  16. count = 0;
  17. }
  18. //13换行一次,否则CR归位键会回到行最左侧位置,导致控制台打印的10-12被吞掉
  19. if (i == 13) {
  20. System.out.println("");
  21. }
  22. char ch = (char) i;
  23. System.out.print("[" + ch + " = " + i + "]\t");
  24. count++;
  25. }
  26. }
  27. }

测试记录:

  1. [ = 8] [ = 9] [
  2. = 10] [ = 11] [ = 12]
  3. [
  4. = 13] [ = 14] [ = 15] [ = 16] [ = 17]
  5. [ = 18] [ = 19] [ = 20] [ = 21] [ = 22]
  6. [ = 23] [ = 24] [ = 25] [ = 26] [ = 27]
  7. [ = 28] [ = 29] [ = 30] [ = 31] [ = 32]
  8. [! = 33] [" = 34] [# = 35] [$ = 36] [% = 37]
  9. [& = 38] [' = 39] [( = 40] [) = 41] [* = 42]
  10. [+ = 43] [, = 44] [- = 45] [. = 46] [/ = 47]
  11. [0 = 48] [1 = 49] [2 = 50] [3 = 51] [4 = 52]
  12. [5 = 53] [6 = 54] [7 = 55] [8 = 56] [9 = 57]
  13. [: = 58] [; = 59] [< = 60] [= = 61] [> = 62]
  14. [? = 63] [@ = 64] [A = 65] [B = 66] [C = 67]
  15. [D = 68] [E = 69] [F = 70] [G = 71] [H = 72]
  16. [I = 73] [J = 74] [K = 75] [L = 76] [M = 77]
  17. [N = 78] [O = 79] [P = 80] [Q = 81] [R = 82]
  18. [S = 83] [T = 84] [U = 85] [V = 86] [W = 87]
  19. [X = 88] [Y = 89] [Z = 90] [[ = 91] [\ = 92]
  20. [] = 93] [^ = 94] [_ = 95] [` = 96] [a = 97]
  21. [b = 98] [c = 99] [d = 100] [e = 101] [f = 102]
  22. [g = 103] [h = 104] [i = 105] [j = 106] [k = 107]
  23. [l = 108] [m = 109] [n = 110] [o = 111] [p = 112]
  24. [q = 113] [r = 114] [s = 115] [t = 116] [u = 117]
  25. [v = 118] [w = 119] [x = 120] [y = 121] [z = 122]
  26. [{ = 123] [| = 124] [} = 125] [~ = 126]

4.2 String类的编解码

方法摘要:
编码 : 把看得懂的变成看不懂的

  1. //使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
  2. public byte[] getBytes(String charsetName) throws UnsupportedEncodingException

解码 : 把看不懂的变成看得懂的

  1. //通过使用指定的 charset解码指定的 byte 数组,构造一个新的 String。
  2. public String(byte[] bytes, String charsetName)

重点强调: 编码和解码的方式需要一致

常见的编码表测试 中文"你"转换为字节数组
UTF-8 => [-28, -67, -96] => JDK8中不指定编码则默认为 UTF-8
GBK/GB2312 => [-60, -29] => JDK7中不指定编码则默认为 GBK/GB2312
ISO-8859-1 => [63]
ASCII => [63]
UNICODE/UTF-16 => [-2, -1, 79, 96] => UNICODE 默认使用的是UTF-16的实现方式

代码:

  1. package Java_study;
  2. import java.io.UnsupportedEncodingException;
  3. import java.util.Arrays;
  4. /**
  5. *
  6. * @author 只是甲
  7. * @date 2021-07-21
  8. * @remark String 类的编解码
  9. *
  10. */
  11. public class io13 {
  12. public static void main(String[] args) throws UnsupportedEncodingException {
  13. //定义一个字符串
  14. String s = "你好";
  15. //a.编码 getBytes => throws UnsupportedEncodingException 不支持的编码异常
  16. byte[] encodeGBK = s.getBytes();
  17. System.out.println(Arrays.toString(encodeGBK));//[-60, -29, -70, -61]
  18. byte[] encodeUTF = s.getBytes("UTF-8");
  19. System.out.println(Arrays.toString(encodeUTF));//[-28, -67, -96, -27, -91, -67]
  20. //b.解码
  21. byte[] bytesGBK = {-60, -29, -70, -61};
  22. String decodeGBK = new String(bytesGBK);
  23. //Java8默认编解码字符集为UTF8 用UTF8解码 GBK编码的字节码文件就会出现乱码
  24. System.out.println(decodeGBK);
  25. String decodeGBKAgain = new String(bytesGBK, "GBK");
  26. //指定用GBK解码
  27. System.out.println(decodeGBKAgain);//你好
  28. byte[] bytesUTF = {-28, -67, -96, -27, -91, -67};
  29. //不指定解码字符集,Java8环境默认使用UTF8字符集进行编解码,刚好和字节数组匹配
  30. String decodeUTF = new String(bytesUTF);
  31. System.out.println(decodeUTF);//你好
  32. }
  33. }

测试记录:

  1. [-60, -29, -70, -61]
  2. [-28, -67, -96, -27, -91, -67]
  3. 你好
  4. 你好
  5. 浣犲ソ

4.3 字符流Stream的编解码(写入文件)

OutputStreamWriter 字符输出流

  1. //根据【默认编码】把字节流的数据转换为字符流
  2. public OutputStreamWriter(OutputStream out)
  3. //根据【指定编码】把字节流数据转换为字符流
  4. public OutputStreamWriter(OutputStream out,String charsetName)

InputStreamReader 字符输入流

  1. //用【默认编码】读数据
  2. public InputStreamReader(InputStream in)
  3. //用【指定编码】读数据
  4. public InputStreamReader(InputStream in,String charsetName)

IDEA设置文件编码

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. *
  5. * @author 只是甲
  6. * @date 2021-07-21
  7. * @remark String 类的编解码
  8. *
  9. */
  10. public class io14 {
  11. public static void main(String[] args) throws IOException{
  12. //指定输出流 目标文件和字符集
  13. OutputStreamWriter oswGBK = new OutputStreamWriter(new FileOutputStream("osw.txt"), "GBK");
  14. //指定输入流 目标文件和字符集
  15. InputStreamReader isrGBK = new InputStreamReader(new FileInputStream("osw.txt"), "GBK");
  16. InputStreamReader isrUTF = new InputStreamReader(new FileInputStream("osw.txt"), "utf-8");
  17. //调用写数据的方法
  18. oswGBK.write("你好");
  19. oswGBK.flush();//刷新缓冲流(执行一次写入)
  20. //用GBK解码GBK文本
  21. int byGBK;
  22. while ((byGBK = isrGBK.read()) != -1) {
  23. System.out.print((char) byGBK);//你好
  24. }
  25. System.out.println("");
  26. //用UTF-解码GBK文本
  27. int byUTF;
  28. while ((byUTF = isrUTF.read()) != -1) {
  29. System.out.print((char) byUTF);//乱码
  30. }
  31. //释放资源
  32. oswGBK.close();
  33. isrGBK.close();
  34. isrUTF.close();
  35. }
  36. }

测试记录:

  1. 你好
  2. ???

五. 字符流

5.1 复制Java文件

需求:
把项目目录下的io1.java内容复制到项目目录下的Copy.java中

三种方式:

  • InputStreamReader & OutputStreamWriter (字符流方式 见5.1) 379毫秒
  • FileReader & FileWriter (字符流方式 见5.1) 297毫秒
  • BufferedReader & BufferedWriter (字符缓冲区流方式 见6.2) 533毫秒

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. *
  5. * @author 只是甲
  6. * @date 2021-07-21
  7. * @remark 字符流 复制Java文件
  8. *
  9. */
  10. public class io15 {
  11. public static void main(String[] args) throws IOException {
  12. long start1 = System.currentTimeMillis();
  13. for (int i = 0; i < 1000; i++) {
  14. method1("io1.java", "Copy.java");//method1共耗时2153毫秒
  15. }
  16. long end1 = System.currentTimeMillis();
  17. System.out.println("method1共耗时"+ (end1 - start1) + "毫秒");
  18. long start2 = System.currentTimeMillis();
  19. for (int i = 0; i < 1000; i++) {
  20. method1("io1.java", "Copy.java");
  21. }
  22. long end2 = System.currentTimeMillis();
  23. System.out.println("method1共耗时"+ (end2 - start2) + "毫秒");
  24. }
  25. public static void method1(String source, String target) throws IOException {
  26. //封装数据源
  27. InputStreamReader isr = new InputStreamReader(new FileInputStream(source));
  28. //封装目的地
  29. OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(target));
  30. char[] chArr = new char[1024];
  31. int len;
  32. while ((len = isr.read(chArr)) != -1) {
  33. osw.write(chArr, 0, len);
  34. }
  35. //释放资源
  36. osw.close();
  37. isr.close();
  38. }
  39. public static void method2(String source, String target) throws IOException{
  40. //封装数据源
  41. FileReader fr = new FileReader(source);
  42. //封装目的地
  43. FileWriter fw = new FileWriter(target);
  44. char[] chArr = new char[1024];
  45. int len;
  46. while ((len = fr.read(chArr)) != -1) {
  47. fw.write(chArr,0,len);
  48. }
  49. //释放资源
  50. fw.close();
  51. fr.close();
  52. }
  53. }

测试记录:

  1. method1共耗时379毫秒
  2. method1共耗时297毫秒

5.2 OutputStreamWriter写数据的6种方式

方法摘要:

  1. /* @introduction 写一个字符
  2. * @param c 要写入的字符
  3. */
  4. public void write(char c)
  5. /* @introduction 写一个字符
  6. * @param c 要写入的字符对应码表中int值
  7. */
  8. public void write(int c)
  9. /* @introduction 写一个字符数组
  10. * @param cbuf 要写入的字符数组
  11. */
  12. public void write(char[] cbuf)
  13. /* @introduction 写一个字符数组的一部分
  14. * @param cbuf 要写入的字符数组
  15. * @param off 起始索引
  16. * @param len 从起始索引起,写入字符数组长度
  17. */
  18. public void write(char[] cbuf,int off,int len)
  19. /* @introduction 写一个字符串
  20. * @param str 要写入的字符串
  21. */
  22. public void write(String str)
  23. /* @introduction 写一个字符串的一部分
  24. * @param str 要写入的字符串
  25. * @param off 起始索引
  26. * @param len 从起始索引起,写入字符串长度
  27. */
  28. public void write(String str,int off,int len)

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. *
  5. * @author 只是甲
  6. * @date 2021-07-21
  7. * @remark OutputStreamWriter写数据的6种方式
  8. *
  9. */
  10. public class io16 {
  11. public static void main(String[] args) throws IOException{
  12. //创建字符输出流对象 (同时创建文件)
  13. OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("target.txt"));
  14. //a. public void write(char c); 写一个字符
  15. methodA(osw);//写入一个字符a
  16. osw.write('\r');//换行
  17. //b. public void write(int c); 写一个字符
  18. methodB(osw);//写入一个字符b
  19. osw.write('\r');//换行
  20. //c. public void write(char[] cbuf); 写一个字符数组
  21. methodC(osw);//写入abcde
  22. osw.write('\r');//换行
  23. //d. public void write(char[] cbuf,int off,int len); 写一个字符数组的一部分
  24. methodD(osw);//写入c
  25. osw.write('\r');//换行
  26. //e. public void write(String str); 写一个字符串
  27. methodE(osw);//写入hello
  28. osw.write('\r');//换行
  29. //f. public void write(String str,int off,int len); 写一个字符串的一部分
  30. methodF(osw);//写入lo
  31. osw.write('\r');//换行
  32. //释放资源
  33. osw.close();//关闭此流,关闭前将缓冲区(内存)字符刷新(flush=>写入硬盘)
  34. }
  35. public static void methodA(OutputStreamWriter osw) throws IOException {
  36. osw.write('a');
  37. }
  38. public static void methodB(OutputStreamWriter osw) throws IOException {
  39. osw.write(98);
  40. }
  41. public static void methodC(OutputStreamWriter osw) throws IOException {
  42. char[] chs = {'a', 'b', 'c', 'd', 'e'};
  43. osw.write(chs);//写入 abcde
  44. }
  45. public static void methodD(OutputStreamWriter osw) throws IOException {
  46. char[] chs = {'a', 'b', 'c', 'd', 'e' };
  47. osw.write(chs, 2, 1);//写入bcd
  48. }
  49. public static void methodE(OutputStreamWriter osw) throws IOException {
  50. String s = "hello";
  51. //e. public void write(String str); 写一个字符串
  52. osw.write(s);//写入hello
  53. //void flush():刷新该流的缓冲
  54. //osw.flush();
  55. }
  56. public static void methodF(OutputStreamWriter osw) throws IOException {
  57. String s = "hello";
  58. //f. public void write(String str,int off,int len); 写一个字符串的一部分
  59. osw.write(s, 3, 2);
  60. //void flush():刷新该流的缓冲
  61. //osw.flush();
  62. }
  63. }

5.3 InputStreamReader读数据的2种方式

方法摘要

  1. //一次读取一个字符
  2. public int read()
  3. //一次读取一个字符数组
  4. public int read(char[] cbuf)

代码:

  1. package Java_study;
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. /**
  6. *
  7. * @author 只是甲
  8. * @date 2021-07-21
  9. * @remark InputStreamReader读数据的2种方式
  10. *
  11. */
  12. public class io17 {
  13. public static void main(String[] args) throws IOException{
  14. //创建字符流输入对象
  15. InputStreamReader isrA = new InputStreamReader(new FileInputStream("a.txt"));
  16. InputStreamReader isrB = new InputStreamReader(new FileInputStream("a.txt"));
  17. //a. public int read(); 一次读取一个字符
  18. methodA(isrA);
  19. System.out.println("\r\n==========================");
  20. //b. public int read(char[] cbuf); 一次读取一个字符数组
  21. methodB(isrB);
  22. //释放资源
  23. isrA.close();
  24. isrB.close();
  25. }
  26. public static void methodA(InputStreamReader isr) throws IOException{
  27. int ch;
  28. while ((ch = isr.read()) != -1) {
  29. System.out.print((char) ch);
  30. }
  31. }
  32. public static void methodB(InputStreamReader isr) throws IOException{
  33. char[] chs = new char[1024];
  34. int len;
  35. while ((len = isr.read(chs)) != -1) {
  36. System.out.println(new String(chs, 0, len));
  37. }
  38. }
  39. }

六. 字符缓冲区流

6.1 概述

BufferedWriter

  • 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
  • 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
  • 构造方法
  1. BufferedWriter(Writer out)

BufferedReader

  • 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
  • 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
  • 构造方法
  1. BufferedReader(Reader in)

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. *
  5. * @author 只是甲
  6. * @date 2021-07-21
  7. * @remark 字符缓冲区流概述
  8. *
  9. */
  10. public class io18 {
  11. public static void main(String[] args) throws IOException{
  12. //创建字符缓冲输出流对象
  13. BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
  14. //调用写数据的方法
  15. bw.write("hello");
  16. //释放资源
  17. bw.close();
  18. //创建字符缓冲输入流对象
  19. BufferedReader br1 = new BufferedReader(new FileReader("io1.java"));
  20. BufferedReader br2 = new BufferedReader(new FileReader("io1.java"));
  21. //方式1:一次读取一个字符
  22. method1(br1);
  23. //方式2:一次读取一个字符数组
  24. method2(br2);
  25. //释放资源
  26. br1.close();
  27. br2.close();
  28. }
  29. public static void method1(BufferedReader br) throws IOException{
  30. int ch;
  31. while((ch=br.read()) != -1) {
  32. System.out.print((char)ch);
  33. }
  34. }
  35. public static void method2(BufferedReader br) throws IOException{
  36. char[] chs = new char[1024];
  37. int len;
  38. while ((len = br.read(chs)) != -1) {
  39. System.out.print(new String(chs, 0, len));
  40. }
  41. }
  42. }

6.2 复制文本文件

需求:

  • 把项目目录下的a.txt内容复制到项目目录下的b.txt中
  • 数据源
     a.txt—读数据—字符流—InputStreamReader—FileReader—BufferedReader
  • 目的地
     b.txt—写数据—字符流—OutputStreamWriter—FileWriter—BufferedWriter

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. *
  5. * @author 只是甲
  6. * @date 2021-07-21
  7. * @remark 字符缓冲区流 复制文本文件
  8. *
  9. */
  10. public class Io19 {
  11. public static void main(String[] args) throws IOException{
  12. //封装数据源
  13. BufferedReader br = new BufferedReader(new FileReader("a.txt"));
  14. //封装目的地
  15. BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
  16. //读写数据
  17. char[] chs = new char[1024];
  18. int len;
  19. while ((len = br.read(chs)) != -1 ) bw.write(chs, 0, len);
  20. //释放资源
  21. bw.close();
  22. br.close();
  23. }
  24. }

6.3 复制Java文件

需求:
把项目目录下的io1.java内容复制到项目目录下的Copy.java中

三种方式:

  • InputStreamReader & OutputStreamWriter (字符流方式 见5.1) 379毫秒
  • FileReader & FileWriter (字符流方式 见5.1) 297毫秒
  • BufferedReader & BufferedWriter (字符缓冲区流方式 见6.2) 533毫秒

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. *
  5. * @author 只是甲
  6. * @date 2021-07-21
  7. * @remark 字符缓冲区流 字符缓冲区流复制Java文件
  8. *
  9. */
  10. public class Io20 {
  11. public static void main(String[] args) throws IOException {
  12. long start3 = System.currentTimeMillis();
  13. for (int i = 0; i < 1000; i++) {
  14. method3("io1.java", "Copy.java");
  15. }
  16. long end3 = System.currentTimeMillis();
  17. System.out.println("method3共耗时"+ (end3 - start3) + "毫秒");
  18. }
  19. public static void method3(String source,String target) throws IOException {
  20. //封装数据源
  21. BufferedReader br = new BufferedReader(new FileReader(source));
  22. //封装目的地
  23. BufferedWriter bw = new BufferedWriter(new FileWriter(target));
  24. //读写数据
  25. String line;
  26. while ((line = br.readLine()) != null) {
  27. bw.write(line);
  28. bw.newLine();
  29. bw.flush();
  30. }
  31. //释放资源
  32. bw.close();
  33. }
  34. }

6.4 字符缓冲区流的特殊功能

BufferedWriter

  1. //写入一个行分隔符,这个行分隔符是由系统决定的
  2. void newLine()

BufferedReader

  1. //包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
  2. String readLine()

代码:

  1. package Java_study;
  2. import java.io.*;
  3. /**
  4. *
  5. * @author 只是甲
  6. * @date 2021-07-21
  7. * @remark 字符缓冲区流 字符缓冲区流复制Java文件
  8. *
  9. */
  10. public class Io21 {
  11. public static void main(String[] args) throws IOException{
  12. //创建字符缓冲输出流对象
  13. BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
  14. //写数据
  15. for (int x = 0; x < 3; x++) {
  16. bw.write("hello");
  17. bw.newLine();
  18. bw.flush();
  19. }
  20. //释放资源
  21. bw.close();
  22. //创建字符缓冲输入流对象
  23. BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
  24. //创建line对象接收每一行数据
  25. String line;
  26. //b. String readLine():包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
  27. while ((line = br.readLine()) != null) {
  28. System.out.println(line);
  29. }
  30. //释放资源
  31. br.close();
  32. }
  33. }

参考:

  1. https://blog.csdn.net/qq_43529621/article/details/116603510
上一篇:file类别

相关文章