title: 【学习之路】IO流学习
draft: true
tags:


Java IO原理

  • IO是Input/Output的缩写,用于处理设备之间的数据传输。如读写文件等。

  • 输入Input:读取外部数据到内存中

  • 输出Output:将程序内存数据输出到磁盘等储存设备

IO流的分类

  • 按照操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
  • 按数据流的流向不同分为:输入流,输出流
  • 按流的角色的不同分为:节点流,处理流

IO流 - 图1

FileReader


read()方法的使用

  • 空参方法
  1. // 实列化File类对象,指明要操作的文件
  2. File file = new File("hello.txt");
  3. // 提供具体的流
  4. FileReader fr = new FileReader(file);
  5. // 数据的读入
  6. // read():返回读入的一个字符,如果达到文件末尾,返回-1
  7. int data = fr.read();
  8. while(data != -1){
  9. System.out.println((char)data);
  10. data = fr.read();
  11. }
  12. // 流的关闭操作
  13. fr.close();
  1. // 读入操作语法上的修改
  2. int data;
  3. while ((data = fr.read()) != -1){
  4. System.out.println((char) data);
  5. }
  1. FileReader fr = null;
  2. try{
  3. // 实列化File对象
  4. File file = new File("D:\\java-code\\JavaSETest\\src\\hello.txt");
  5. // 实列化FileReader对象将File对象传入
  6. fr = new FileReader(file);
  7. // 数据的读入
  8. // read():返回读入的一个字符如果达到末尾,返回-1
  9. int data;
  10. while ((data = fr.read()) != -1){
  11. System.out.println((char) data);
  12. }
  13. }catch (IOException e){
  14. e.printStackTrace();
  15. }finally {
  16. // 流的关闭操作
  17. try {
  18. if (fr != null) {
  19. fr.close();
  20. }
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. }
  24. }
  • char[]重载方法
  1. FileReader fr = null;
  2. try{
  3. File file = new File("D:\\java-code\\JavaSETest\\src\\hello.txt");
  4. fr = new FileReader(file);
  5. // 读入操作
  6. char[] cbuf = new char[5];
  7. int len;
  8. while ((len = fr.read(cbuf)) != -1){
  9. // 错误的写法
  10. for (int i = 0; i < cbuf.length; i++) {
  11. System.out.print(cbuf[i]);
  12. }
  13. }
  14. }catch (Exception e){
  15. e.printStackTrace();
  16. }finally{
  17. // 关闭流的操作
  18. try {
  19. if (fr != null) {
  20. fr.close();
  21. }
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. }
  25. }

这样写输出有问题,每次写入都是覆盖数组的操作,如果读到最后一次没有5个字符那么上次读取剩下来的字符就会保留

IO流 - 图2%E9%94%99%E8%AF%AF%E8%BE%93%E5%87%BA.png#alt=read%28%29%E9%94%99%E8%AF%AF%E8%BE%93%E5%87%BA)

正确的写法

  1. FileReader fr = null;
  2. try{
  3. File file = new File("D:\\java-code\\JavaSETest\\src\\hello.txt");
  4. fr = new FileReader(file);
  5. // 读入操作
  6. char[] cbuf = new char[5];
  7. int len;
  8. while ((len = fr.read(cbuf)) != -1){
  9. // 错误的写法
  10. // for (int i = 0; i < cbuf.length; i++) {
  11. // System.out.print(cbuf[i]);
  12. // }
  13. // 正确的写法
  14. for (int i = 0; i < len; i++) {
  15. System.out.print(cbuf[i]);
  16. }
  17. }
  18. }catch (Exception e){
  19. e.printStackTrace();
  20. }finally{
  21. // 关闭流的操作
  22. try {
  23. if (fr != null) {
  24. fr.close();
  25. }
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. }

IO流 - 图3%E6%AD%A3%E7%A1%AE%E8%BE%93%E5%87%BA.png#alt=read%28%29%E6%AD%A3%E7%A1%AE%E8%BE%93%E5%87%BA)

或者使用String的构造器来获取

  1. // 读入操作
  2. char[] cbuf = new char[5];
  3. int len;
  4. while ((len = fr.read(cbuf)) != -1){
  5. // 错误写法
  6. // String str = new String(cbuf);
  7. // System.out.print(str);
  8. // 正确写法 获取数组,从第0位置到len的位置
  9. String str = new String(cbuf, 0, len);
  10. System.out.print(str);
  11. }

FileWriter

输出操作,对应的File可以不存在

如果不存在,那么就会自动创建此文件

如果存在:如果流使用的构造器是:FileWriter(file, true):再原有文件追加内容 / FileWriter(File):对原有文件的覆盖

writer()方法的使用

  1. FileWriter fw = null;
  2. try{
  3. File file = new File("D:\\java-code\\JavaSETest\\src\\hello1.txt");
  4. // 覆盖原有文件
  5. fw = new FileWriter(file);
  6. // 追加原有文件
  7. // fw = new FileWriter(file, true);
  8. fw.write("CodeXuan");
  9. }catch (Exception e){
  10. e.printStackTrace();
  11. }finally{
  12. try {
  13. if (fw != null) {
  14. fw.close();
  15. }
  16. } catch (IOException e) {
  17. e.printStackTrace();
  18. }
  19. }

File Input/Output Stream

如果使用字节流读取文件可能会出现乱码问题

  1. File file = new File("D:\\java-code\\JavaSETest\\src\\hello.txt");
  2. FileInputStream fis = null;
  3. try{
  4. // 创建流
  5. fis = new FileInputStream(file);
  6. // 读取数据
  7. byte[] buffer = new byte[5];
  8. int len;
  9. while ((len = fis.read(buffer)) != -1){
  10. String str = new String(buffer, 0, len);
  11. System.out.print(str);
  12. }
  13. }catch (Exception e){
  14. e.printStackTrace();
  15. }finally{
  16. try {
  17. if (fis != null) {
  18. fis.close();
  19. }
  20. } catch (IOException e) {
  21. e.printStackTrace();
  22. }
  23. }

使用字节流复制文件,也可以使用字节流复制文本文件,但是最好不要再内存层面读取否则有可能出现乱码的情况

  1. long start = System.currentTimeMillis();
  2. File srcFile = new File("background.png");
  3. File destFile = new File("background-副本.png");
  4. FileInputStream fis = null;
  5. FileOutputStream fos = null;
  6. try{
  7. fis = new FileInputStream(srcFile);
  8. fos = new FileOutputStream(destFile);
  9. // 复制操作
  10. byte[] bytes = new byte[1024];
  11. int len;
  12. while ((len = fis.read(bytes)) != -1) {
  13. fos.write(bytes, 0, len);
  14. }
  15. System.out.println("复制成功");
  16. }catch (Exception e){
  17. e.printStackTrace();
  18. }finally{
  19. try {
  20. if (fis != null) {
  21. fis.close();
  22. }
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. try {
  27. if (fos != null) {
  28. fos.close();
  29. }
  30. } catch (IOException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. long end = System.currentTimeMillis();
  35. System.out.println("复制花费的时间" + (end - start));

Buffered Input/Output Stream

  1. long start = System.currentTimeMillis();
  2. File srcFile = new File("background.png");
  3. File destFile = new File("background-副本.png");
  4. FileInputStream fis = null;
  5. FileOutputStream fos = null;
  6. BufferedInputStream bis = null;
  7. BufferedOutputStream bos = null;
  8. try{
  9. // 创建节点流
  10. fis = new FileInputStream(srcFile);
  11. fos = new FileOutputStream(destFile);
  12. // 创建缓冲流
  13. bis = new BufferedInputStream(fis);
  14. bos = new BufferedOutputStream(fos);
  15. // 复制细节
  16. byte[] bytes = new byte[1024];
  17. int len;
  18. while ((len = bis.read(bytes)) != -1){
  19. bos.write(bytes, 0, len);
  20. }
  21. System.out.println("复制成功");
  22. }catch (Exception e){
  23. e.printStackTrace();
  24. }finally{
  25. // 资源关闭
  26. // 要求:先关闭外层流,再关闭内层流
  27. // 关闭外层流后,内层流会自动关闭,内层流的关闭可以省略
  28. try {
  29. if (bis != null) {
  30. bis.close();
  31. }
  32. } catch (IOException e) {
  33. e.printStackTrace();
  34. }
  35. try {
  36. if (bos != null) {
  37. bos.close();
  38. }
  39. } catch (IOException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. long end = System.currentTimeMillis();
  44. System.out.println("复制花费的时间" + (end - start));

BufferedReader/Writer

  • 方式一
  1. BufferedReader br = null;
  2. BufferedWriter bw = null;
  3. try {
  4. br = new BufferedReader(new FileReader("hello.txt"));
  5. bw = new BufferedWriter(new FileWriter("hello-副本.txt"));
  6. char[] chars = new char[1024];
  7. int len;
  8. while ((len = br.read(chars)) != -1){
  9. bw.write(chars, 0, len);
  10. }
  11. } catch (IOException e) {
  12. e.printStackTrace();
  13. } finally {
  14. try {
  15. if (br != null) {
  16. br.close();
  17. }
  18. } catch (IOException e) {
  19. e.printStackTrace();
  20. }
  21. try {
  22. if (bw != null) {
  23. bw.close();
  24. }
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
  • 方式二
  1. BufferedReader br = null;
  2. BufferedWriter bw = null;
  3. try {
  4. br = new BufferedReader(new FileReader("hello.txt"));
  5. bw = new BufferedWriter(new FileWriter("hello-副本.txt"));
  6. String data;
  7. // readLine()一次读一行,使用这种方法不包含换行符
  8. while ((data = br.readLine()) != null){
  9. // 方式一:增加换行符
  10. // bw.write(data + "\n");
  11. // 方式二:增加换行符
  12. bw.write(data);
  13. bw.newLine();
  14. }
  15. } catch (IOException e) {
  16. e.printStackTrace();
  17. } finally {
  18. try {
  19. if (br != null) {
  20. br.close();
  21. }
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. }
  25. try {
  26. if (bw != null) {
  27. bw.close();
  28. }
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }

InputStreamReader

  • 将一个字节的输入流转换为字符的输入流
  1. InputStreamReader isr = null;
  2. try {
  3. FileInputStream fis = new FileInputStream("hello.txt");
  4. // 参数二指明字符集,具体使用的字符集,取决于文件保存时使用的字符集
  5. isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
  6. char[] chars = new char[20];
  7. int len;
  8. while ((len = isr.read(chars)) != -1){
  9. String str = new String(chars, 0, len);
  10. System.out.println(str);
  11. }
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. } finally {
  15. try {
  16. if (isr != null) {
  17. isr.close();
  18. }
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }

OutputStreamWriter

  • 将一个字符的输出流转换为字节的输出流
  1. InputStreamReader isr = null;
  2. OutputStreamWriter osw = null;
  3. try {
  4. // 获取文件
  5. File file1 = new File("hello.txt");
  6. File file2 = new File("hello-gbk.txt");
  7. FileInputStream fis = new FileInputStream(file1);
  8. FileOutputStream fos = new FileOutputStream(file2);
  9. isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
  10. osw = new OutputStreamWriter(fos, "GBK");
  11. // 读写过程
  12. char[] cbuf = new char[20];
  13. int len;
  14. while ((len = isr.read(cbuf)) != -1){
  15. osw.write(cbuf, 0, len);
  16. }
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. } finally {
  20. // 关闭流
  21. try {
  22. if (isr != null) {
  23. isr.close();
  24. }
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. try {
  29. if (osw != null) {
  30. osw.close();
  31. }
  32. } catch (IOException e) {
  33. e.printStackTrace();
  34. }
  35. }