第7章 IO流 - IO流之File类

优质
小牛编辑
128浏览
2023-12-01

typora-copy-images-to: img

1. File类概述

File类用于封装一个路径,这个路径可以是从系统盘符开始的绝对路径,如:“D:\file\a.txt”,也可以是相对于当前目录而言的相对路径,如:“src\Hello.java”。File类内部封装的路径可以指向一个文件,也可以指向一个目录,在File类中提供了针对这些文件或目录的一些常规操作。

文件和目录路径名的抽象表示形式,表示一个文件或文件夹,并提供了一系列操作文件或文件夹的方法

File类中提供了一系列方法,用于操作其内部封装的路径指向的文件或者目录,例如判断文件/目录是否存在、创建、删除文件/目录等。

1500708828607

2. 构造方法

方法功能描述
File(String pathname)根据路径得到File对象
File(String parent,String child)根据目录和子文件/目录得到对象
File(File parent,String child)根据父File对象和子文件/目录得到对象

示例代码

  1. package cn.itcast_01;
  2. import java.io.File;
  3. /*
  4. * 我们要想实现IO的操作,就必须知道硬盘上文件的表现形式。
  5. * 而Java就提供了一个类File供我们使用。
  6. *
  7. * File:文件和目录(文件夹)路径名的抽象表示形式
  8. * 构造方法:
  9. * File(String pathname):根据一个路径得到File对象
  10. * File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
  11. * File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
  12. */
  13. public class FileDemo {
  14. public static void main(String[] args) {
  15. // File(String pathname):根据一个路径得到File对象
  16. // 把e:\\demo\\a.txt封装成一个File对象
  17. File file = new File("E:\\demo\\a.txt");
  18. // File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
  19. File file2 = new File("E:\\demo", "a.txt");
  20. // File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
  21. File file3 = new File("e:\\demo");
  22. File file4 = new File(file3, "a.txt");
  23. // 以上三种方式其实效果一样
  24. }
  25. }

3. 创建功能

返回值方法功能描述
booleancreateNewFile()创建文件
FilecreateTempFile()创建一个用于缓存的临时文件
booleanmkdir()创建文件夹
booleanmkdirs()创建多级文件夹,如果父级文件夹不存在,会自动创建

代码示例

  1. package cn.itcast_02;
  2. import java.io.File;
  3. import java.io.IOException;
  4. /*
  5. *创建功能:
  6. *public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
  7. *public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
  8. *public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
  9. */
  10. public class FileDemo {
  11. public static void main(String[] args) throws IOException {
  12. // 需求:我要在e盘目录下创建一个文件夹demo
  13. File file = new File("e:\\demo");
  14. System.out.println("mkdir:" + file.mkdir());
  15. // 需求:我要在e盘目录demo下创建一个文件a.txt
  16. File file2 = new File("e:\\demo\\a.txt");
  17. System.out.println("createNewFile:" + file2.createNewFile());
  18. // 需求:我要在e盘目录test下创建一个文件b.txt
  19. // Exception in thread "main" java.io.IOException: 系统找不到指定的路径。
  20. // 注意:要想在某个目录下创建内容,该目录首先必须存在。
  21. // File file3 = new File("e:\\test\\b.txt");
  22. // System.out.println("createNewFile:" + file3.createNewFile());
  23. // 需求:我要在e盘目录test下创建aaa目录
  24. // File file4 = new File("e:\\test\\aaa");
  25. // System.out.println("mkdir:" + file4.mkdir());
  26. // File file5 = new File("e:\\test");
  27. // File file6 = new File("e:\\test\\aaa");
  28. // System.out.println("mkdir:" + file5.mkdir());
  29. // System.out.println("mkdir:" + file6.mkdir());
  30. // 其实我们有更简单的方法
  31. File file7 = new File("e:\\aaa\\bbb\\ccc\\ddd");
  32. System.out.println("mkdirs:" + file7.mkdirs());
  33. // 看下面的这个东西:
  34. File file8 = new File("e:\\liuyi\\a.txt");
  35. System.out.println("mkdirs:" + file8.mkdirs());
  36. }
  37. }

4. 删除功能

返回值方法功能描述
booleandelete()删除文件或文件夹
voiddeleteOnExit()JVM退出时删除File对象对应的文件和目录

代码示例

  1. package cn.itcast_03;
  2. import java.io.File;
  3. import java.io.IOException;
  4. /*
  5. * 删除功能:public boolean delete()
  6. *
  7. * 注意:
  8. * A:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。
  9. * B:Java中的删除不走回收站。
  10. * C:要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
  11. */
  12. public class FileDemo {
  13. public static void main(String[] args) throws IOException {
  14. // 创建文件
  15. // File file = new File("e:\\a.txt");
  16. // System.out.println("createNewFile:" + file.createNewFile());
  17. // 我不小心写成这个样子了
  18. File file = new File("a.txt");
  19. System.out.println("createNewFile:" + file.createNewFile());
  20. // 继续玩几个
  21. File file2 = new File("aaa\\bbb\\ccc");
  22. System.out.println("mkdirs:" + file2.mkdirs());
  23. // 删除功能:我要删除a.txt这个文件
  24. File file3 = new File("a.txt");
  25. System.out.println("delete:" + file3.delete());
  26. // 删除功能:我要删除ccc这个文件夹
  27. File file4 = new File("aaa\\bbb\\ccc");
  28. System.out.println("delete:" + file4.delete());
  29. // 删除功能:我要删除aaa文件夹
  30. // File file5 = new File("aaa");
  31. // System.out.println("delete:" + file5.delete());
  32. File file6 = new File("aaa\\bbb");
  33. File file7 = new File("aaa");
  34. System.out.println("delete:" + file6.delete());
  35. System.out.println("delete:" + file7.delete());
  36. }
  37. }

5. 重命名功能

方法功能描述
renamneTo(File dest)路径名相同就是重命名,不一样就是改名加剪切

代码示例

  1. package cn.itcast_04;
  2. import java.io.File;
  3. /*
  4. * 重命名功能:public boolean renameTo(File dest)
  5. * 如果路径名相同,就是改名。
  6. * 如果路径名不同,就是改名并剪切。
  7. *
  8. * 路径以盘符开始:绝对路径 c:\\a.txt
  9. * 路径不以盘符开始:相对路径 a.txt
  10. */
  11. public class FileDemo {
  12. public static void main(String[] args) {
  13. // 创建一个文件对象
  14. // File file = new File("林青霞.jpg");
  15. // // 需求:我要修改这个文件的名称为"东方不败.jpg"
  16. // File newFile = new File("东方不败.jpg");
  17. // System.out.println("renameTo:" + file.renameTo(newFile));
  18. File file2 = new File("东方不败.jpg");
  19. File newFile2 = new File("e:\\林青霞.jpg");
  20. System.out.println("renameTo:" + file2.renameTo(newFile2));
  21. }
  22. }

6. 判断功能

方法功能描述
isDirectory()判断是否是目录
isFile()判断是否是文件
exists()判断是否是存在
canRead()判断是否是可读
canWrite()判断是否是可写
isHidden()判断是否是隐藏
isAbsolute()是否是绝对路径

示例代码

  1. import java.io.File;
  2. /*
  3. * 判断功能:
  4. * public boolean isDirectory():判断是否是目录
  5. * public boolean isFile():判断是否是文件
  6. * public boolean exists():判断是否存在
  7. * public boolean canRead():判断是否可读
  8. * public boolean canWrite():判断是否可写
  9. * public boolean isHidden():判断是否隐藏
  10. */
  11. public class FileDemo {
  12. public static void main(String[] args) {
  13. // 创建文件对象
  14. File file = new File("a.txt");
  15. System.out.println("isDirectory:" + file.isDirectory());// false
  16. System.out.println("isFile:" + file.isFile());// true
  17. System.out.println("exists:" + file.exists());// true
  18. System.out.println("canRead:" + file.canRead());// true
  19. System.out.println("canWrite:" + file.canWrite());// true
  20. System.out.println("isHidden:" + file.isHidden());// false
  21. }
  22. }

7. 获取功能

返回值方法功能描述
StringgetAbsolutePath()获取绝对路径
StringgetPath()获取相对路径
StringgetParent()获取父目录
StringgetName()获取名称
longgetFreeSpace()获取剩余可用空间
longgetTotalSpace()获取总大小
longlength()获取长度,字节数
longlastModified()获取最后一次修改时间,毫秒值
String[]list()获取指定目录下的所有文件或文件夹的名称数组
File[]listFiles()获取指定目录下的所有文件或文件夹的File数组

代码示例

  1. package cn.itcast_06;
  2. import java.io.File;
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5. /*
  6. * 获取功能:
  7. * public String getAbsolutePath():获取绝对路径
  8. * public String getPath():获取相对路径
  9. * public String getName():获取名称
  10. * public long length():获取长度。字节数
  11. * public long lastModified():获取最后一次的修改时间,毫秒值
  12. */
  13. public class FileDemo {
  14. public static void main(String[] args) {
  15. // 创建文件对象
  16. File file = new File("demo\\test.txt");
  17. System.out.println("getAbsolutePath:" + file.getAbsolutePath());
  18. System.out.println("getPath:" + file.getPath());
  19. System.out.println("getName:" + file.getName());
  20. System.out.println("length:" + file.length());
  21. System.out.println("lastModified:" + file.lastModified());
  22. // 1416471971031
  23. Date d = new Date(1416471971031L);
  24. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  25. String s = sdf.format(d);
  26. System.out.println(s);
  27. }
  28. }

运行结果:

  1. getAbsolutePath:D:\workspace\Test\demo\test.txt
  2. getPath:demo\test.txt
  3. getName:test.txt
  4. length:0
  5. lastModified:0
  6. 2014-11-20 16:26:11

判断缓存文件是否过期

  1. File file = ...;
  2. long time = System.currentTimeMillis() - file.lastModified();
  3. if (time < cachetime){
  4. // 缓存时间小于指定的时间,缓存有效,否则缓存过期
  5. }else {
  6. }

8. 高级获取功能

返回值方法功能描述
String[]list(FilenameFilter filter)返回满足条件的文件名数组
File[]listFiles(FilenameFilter filter)返回满足条件的文件数组
File[]listRoots()列出系统所有的根路径
  1. package cn.itcast_07;
  2. import java.io.File;
  3. /*
  4. * 高级获取功能:
  5. * public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
  6. * public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
  7. */
  8. public class FileDemo {
  9. public static void main(String[] args) {
  10. // 指定一个目录
  11. File file = new File("e:\\");
  12. // public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
  13. String[] strArray = file.list();
  14. for (String s : strArray) {
  15. System.out.println(s);
  16. }
  17. System.out.println("------------");
  18. // public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
  19. File[] fileArray = file.listFiles();
  20. for (File f : fileArray) {
  21. System.out.println(f.getName());
  22. }
  23. }
  24. }

运行结果:

9. 文件过滤器

  • list(FilenameFilter filter)
  • listFiles(FilenameFilter filter)

FilenameFilter 接口

  • accept(File dir, String name)

10. File练习

文件名称过滤器的实现思想及代码

  • public String[] list(FilenameFilter filter)
  • public File[] listFiles(FilenameFilter filter)

10.1 文件名称过滤器的实现

  1. package cn.itcast_08;
  2. import java.io.File;
  3. import java.io.FilenameFilter;
  4. /*
  5. * 判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称
  6. * A:先获取所有的,然后遍历的时候,依次判断,如果满足条件就输出。
  7. * B:获取的时候就已经是满足条件的了,然后输出即可。
  8. *
  9. * 要想实现这个效果,就必须学习一个接口:文件名称过滤器
  10. * public String[] list(FilenameFilter filter)
  11. * public File[] listFiles(FilenameFilter filter)
  12. */
  13. public class FileDemo2 {
  14. public static void main(String[] args) {
  15. // 封装e判断目录
  16. File file = new File("e:\\");
  17. // 获取该目录下所有文件或者文件夹的String数组
  18. // public String[] list(FilenameFilter filter)
  19. String[] strArray = file.list(new FilenameFilter() {
  20. @Override
  21. public boolean accept(File dir, String name) {
  22. // return false;
  23. // return true;
  24. // 通过这个测试,我们就知道了,到底把这个文件或者文件夹的名称加不加到数组中,取决于这里的返回值是true还是false
  25. // 所以,这个的true或者false应该是我们通过某种判断得到的
  26. // System.out.println(dir + "---" + name);
  27. // File file = new File(dir, name);
  28. // // System.out.println(file);
  29. // boolean flag = file.isFile();
  30. // boolean flag2 = name.endsWith(".jpg");
  31. // return flag && flag2;
  32. return new File(dir, name).isFile() && name.endsWith(".jpg");
  33. }
  34. });
  35. // 遍历
  36. for (String s : strArray) {
  37. System.out.println(s);
  38. }
  39. }
  40. }

10.2 递归遍历目录下指定后缀名结尾的文件名称

  1. package cn.itcast_03;
  2. import java.io.File;
  3. /*
  4. * 需求:把E:\JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。
  5. *
  6. * 分析:
  7. * A:封装目录
  8. * B:获取该目录下所有的文件或者文件夹的File数组
  9. * C:遍历该File数组,得到每一个File对象
  10. * D:判断该File对象是否是文件夹
  11. * 是:回到B
  12. * 否:继续判断是否以.java结尾
  13. * 是:就输出该文件的绝对路径
  14. * 否:不搭理它
  15. */
  16. public class FilePathDemo {
  17. public static void main(String[] args) {
  18. // 封装目录
  19. File srcFolder = new File("E:\\JavaSE");
  20. // 递归功能实现
  21. getAllJavaFilePaths(srcFolder);
  22. }
  23. private static void getAllJavaFilePaths(File srcFolder) {
  24. // 获取该目录下所有的文件或者文件夹的File数组
  25. File[] fileArray = srcFolder.listFiles();
  26. // 遍历该File数组,得到每一个File对象
  27. for (File file : fileArray) {
  28. // 判断该File对象是否是文件夹
  29. if (file.isDirectory()) {
  30. getAllJavaFilePaths(file);
  31. } else {
  32. // 继续判断是否以.java结尾
  33. if (file.getName().endsWith(".java")) {
  34. // 就输出该文件的绝对路径
  35. System.out.println(file.getAbsolutePath());
  36. }
  37. }
  38. }
  39. }
  40. }

运行结果:

10.3 递归删除带内容的目录

  1. package cn.itcast_03;
  2. import java.io.File;
  3. /*
  4. * 需求:递归删除带内容的目录
  5. *
  6. * 分析:
  7. * A:封装目录
  8. * B:获取该目录下的所有文件或者文件夹的File数组
  9. * C:遍历该File数组,得到每一个File对象
  10. * D:判断该File对象是否是文件夹
  11. * 是:回到B
  12. * 否:就删除
  13. */
  14. public class FileDeleteDemo {
  15. public static void main(String[] args) {
  16. // 封装目录
  17. File srcFolder = new File("demo");
  18. // 递归实现
  19. deleteFolder(srcFolder);
  20. }
  21. private static void deleteFolder(File srcFolder) {
  22. // 获取该目录下的所有文件或者文件夹的File数组
  23. File[] fileArray = srcFolder.listFiles();
  24. if (fileArray != null) {
  25. // 遍历该File数组,得到每一个File对象
  26. for (File file : fileArray) {
  27. // 判断该File对象是否是文件夹
  28. if (file.isDirectory()) {
  29. deleteFolder(file);
  30. } else {
  31. System.out.println(file.getName() + "---" + file.delete());
  32. }
  33. }
  34. System.out.println(srcFolder.getName() + "---" + srcFolder.delete());
  35. }
  36. }
  37. }

运行结果:

10.4 模拟文件管理器

DocumentManager

  1. package cn.itcast.chapter07.task03;
  2. import java.io.File;
  3. import java.util.ArrayList;
  4. import java.util.Scanner;
  5. public class DocumentManager {
  6. public static void main(String[] args) throws Exception {
  7. Scanner sc = new Scanner(System.in);
  8. System.out.println("--1:指定关键字检索文件 2:指定后缀名检索文件 " + "3:复制文件/目录 4:退出--");
  9. while (true) {
  10. System.out.print("请输入指令:");
  11. int command = sc.nextInt();
  12. switch (command) {
  13. case 1:
  14. searchByKeyWorld();// 指定关键字检索文件
  15. break;
  16. case 2:
  17. searchBySuffix();// 指定后缀名检索文件
  18. break;
  19. case 3:
  20. copyDirectory();// 复制文件/目录
  21. break;
  22. case 4:
  23. exit();// 退出
  24. break;
  25. default:
  26. System.out.println("您输入的指令错误!");
  27. break;
  28. }
  29. }
  30. }
  31. // *********1.指定关键字检索文件*********
  32. private static void searchByKeyWorld() {
  33. Scanner sc = new Scanner(System.in);
  34. System.out.print("请输入要检索的目录位置:");
  35. String path = sc.next();// 从控制台获取路径
  36. File file = new File(path);
  37. if (!file.exists() || !file.isDirectory()) {// 判断目录是否存在,是否是目录
  38. System.out.println(path + " (不是有效目录)");
  39. return;
  40. }
  41. System.out.print("请输入搜索关键字:");
  42. String key = sc.next();// 获取关键字
  43. // 在输入目录下获取所有包含关键字的文件路径
  44. ArrayList<String> list = FileUtils.listFiles(file, key);
  45. for (Object obj : list) {
  46. System.out.println(obj);// 将路径打印到控制台
  47. }
  48. }
  49. // *********2.指定后缀名检索文件********//
  50. private static void searchBySuffix() {
  51. Scanner sc = new Scanner(System.in);
  52. System.out.print("请输入要检索的目录位置:");
  53. String path = sc.next();// 从控制台获取路径
  54. File file = new File(path);
  55. if (!file.exists() || !file.isDirectory()) {// 判断目录是否存在,是否是目录
  56. System.out.println(path + " (不是有效目录)");
  57. return;
  58. }
  59. System.out.print("请输入搜索后缀:");
  60. String suffix = sc.next();
  61. String[] suffixArray = suffix.split(",");// 获取后缀字符串
  62. // 在输入目录下获取所有指定后缀名的文件路径
  63. ArrayList<String> list = FileUtils.listFiles(file, suffixArray);
  64. for (Object obj : list) {
  65. System.out.println(obj);// 将路径打印到控制台
  66. }
  67. }
  68. // *********3.复制文件/目录**********//
  69. private static void copyDirectory() throws Exception {
  70. Scanner sc = new Scanner(System.in);
  71. System.out.print("请输入源目录:");
  72. String srcDirectory = sc.next();// 从控制台获取源路径
  73. File srcFile = new File(srcDirectory);
  74. if (!srcFile.exists() || !srcFile.isDirectory()) {// 判断目录是否存在,是否是目录
  75. System.out.println("无效目录!");
  76. return;
  77. }
  78. System.out.print("请输入目标位置:");
  79. String destDirectory = sc.next();// 从控制台获取目标路径
  80. File destFile = new File(destDirectory);
  81. if (!destFile.exists() || !destFile.isDirectory()) {// 判断目录是否存在,是否是目录
  82. System.out.println("无效位置!");
  83. return;
  84. }
  85. // 将源路径中的内容复制到目标路径下
  86. FileUtils.copySrcPathToDestPath(srcFile, destFile);
  87. }
  88. // *********4.退出**********//
  89. private static void exit() {
  90. System.out.println("您已退出系统,谢谢使用!");
  91. System.exit(0);
  92. }
  93. }

FileUtils

  1. package cn.itcast.chapter07.task03;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.FilenameFilter;
  6. import java.util.ArrayList;
  7. public class FileUtils {
  8. /**
  9. * 指定关键字检索文件
  10. * @param file File对象
  11. * @param key 关键字
  12. * @return 包含关键字的文件路径
  13. */
  14. public static ArrayList<String> listFiles(File file, final String key) {
  15. FilenameFilter filter = new FilenameFilter() { // 创建过滤器对象
  16. public boolean accept(File dir, String name) {// 实现accept()方法
  17. File currFile = new File(dir, name);
  18. // 如果文件名包含关键字返回true,否则返回false
  19. if (currFile.isFile() && name.contains(key)) {
  20. return true;
  21. }
  22. return false;
  23. }
  24. };
  25. // 递归方式获取规定的路径
  26. ArrayList<String> arraylist = fileDir(file, filter);
  27. return arraylist;
  28. }
  29. /**
  30. * 指定后缀名检索文件
  31. * @param file File对象
  32. * @param suffixArray 后缀名数组
  33. * @return 指定后缀名的文件路径
  34. */
  35. public static ArrayList<String> listFiles(File file,
  36. final String[] suffixArray) {
  37. FilenameFilter filter = new FilenameFilter() { // 创建过滤器对象
  38. public boolean accept(File dir, String name) {// 实现accept()方法
  39. File currFile = new File(dir, name);
  40. if (currFile.isFile()) {// 如果文件名以指定后缀名结尾返回true,否则返回false
  41. for (String suffix : suffixArray) {
  42. if (name.endsWith("." + suffix)) {
  43. return true;
  44. }
  45. }
  46. }
  47. return false;
  48. }
  49. };
  50. // 递归方式获取规定的路径
  51. ArrayList<String> arraylist = fileDir(file, filter);
  52. return arraylist;
  53. }
  54. /**
  55. * 递归方式获取规定的路径
  56. * @param dir File对象
  57. * @param filter 过滤器
  58. * @return 过滤器过滤后的文件路径
  59. */
  60. public static ArrayList<String> fileDir(File dir, FilenameFilter filter) {
  61. ArrayList<String> arraylist = new ArrayList<String>();
  62. File[] lists = dir.listFiles(filter); // 获得过滤后的所有文件数组
  63. for (File list : lists) {
  64. // 将文件的绝对路径放到集合中
  65. arraylist.add(list.getAbsolutePath());
  66. }
  67. File[] files = dir.listFiles(); // 获得当前目录下所有文件的数组
  68. for (File file : files) { // 遍历所有的子目录和文件
  69. if (file.isDirectory()) {
  70. // 如果是目录,递归调用fileDir()
  71. ArrayList<String> every = fileDir(file, filter);
  72. arraylist.addAll(every);// 将文件夹下的文件路径添加到集合中
  73. }
  74. }// 此时的集合中有当前目录下的文件路径,和当前目录的子目录下的文件路径
  75. return arraylist;
  76. }
  77. /**
  78. * 复制文件/目录
  79. * @param srcFile 源目录
  80. * @param destFile 目标目录
  81. */
  82. public static void copySrcPathToDestPath(File srcDir, File destDir)
  83. throws Exception {
  84. File[] files = srcDir.listFiles();// 子文件目录
  85. for (int i = 0; i < files.length; i++) {
  86. File copiedFile = new File(destDir, files[i].getName());// 创建指定目录的文件
  87. if (files[i].isDirectory()) {// 如果是目录
  88. if (!copiedFile.mkdirs()) {// 创建文件夹
  89. System.out.println("无法创建:" + copiedFile);
  90. return;
  91. }
  92. // 调用递归,获取子文件夹下的文件路径
  93. copySrcPathToDestPath(files[i], copiedFile);
  94. } else {// 复制文件
  95. FileInputStream input = new FileInputStream(files[i]);// 获取输入流
  96. FileOutputStream output = new FileOutputStream(copiedFile);// 获取输出流
  97. byte[] buffer = new byte[1024];// 创建缓冲区
  98. int n = 0;
  99. // 循环读取字节
  100. while ((n = input.read(buffer)) != -1) {
  101. output.write(buffer, 0, n);
  102. }
  103. input.close();// 关闭输入流
  104. output.close();// 关闭输出流
  105. }
  106. }
  107. }
  108. }