一、File文件/夹操作

在计算机系统中,文件是非常重要的存储方式。Java的标准库java.io提供了File对象来操作文件和目录。
要构造一个File对象,需要传入文件路径:

  1. public class Main {
  2. public static void main(String[] args) {
  3. File f = new File("C:\\Windows\\notepad.exe");
  4. System.out.println(f); //C:\Windows\notepad.exe
  5. }
  6. }

构造File对象时,既可以传入绝对路径,也可以传入相对路径。绝对路径是以根目录开头的完整路径,例如:

  1. File f = new File("C:\\Windows\\notepad.exe");

注意Windows平台使用\作为路径分隔符,在Java字符串中需要用\\表示一个\。Linux平台使用/作为路径分隔符:

  1. File f = new File("/usr/bin/javac");

传入相对路径时,相对路径前面加上当前目录就是绝对路径:

  1. // 假设当前目录是C:\Docs
  2. File f1 = new File("sub\\javac"); // 绝对路径是C:\Docs\sub\javac
  3. File f3 = new File(".\\sub\\javac"); // 绝对路径是C:\Docs\sub\javac
  4. File f3 = new File("..\\sub\\javac"); // 绝对路径是C:\sub\javac

可以用.表示当前目录,..表示上级目录。
File对象有3种形式表示的路径,一种是getPath(),返回构造方法传入的路径,一种是getAbsolutePath(),返回绝对路径,一种是getCanonicalPath,它和绝对路径类似,但是返回的是规范路径。
什么是规范路径?我们看以下代码:

  1. public class Main {
  2. public static void main(String[] args) throws IOException {
  3. File f = new File("..");
  4. System.out.println(f.getPath()); //..
  5. System.out.println(f.getAbsolutePath()); // /app/..
  6. System.out.println(f.getCanonicalPath()); // /
  7. }
  8. }

绝对路径可以表示成C:\Windows\System32\..\notepad.exe,而规范路径就是把...转换成标准的绝对路径后的路径:C:\Windows\notepad.exe
因为Windows和Linux的路径分隔符不同,File对象有一个静态变量用于表示当前平台的系统分隔符:

  1. System.out.println(File.separator); // 根据当前平台打印"\"或"/"

1.文件和目录

File对象既可以表示文件,也可以表示目录。特别要注意的是,构造一个File对象,即使传入的文件或目录不存在,代码也不会出错,因为构造一个File对象,并不会导致任何磁盘操作。只有当我们调用File对象的某些方法的时候,才真正进行磁盘操作。
例如,调用isFile(),判断该File对象是否是一个已存在的文件,调用isDirectory(),判断该File对象是否是一个已存在的目录:

  1. public class Main {
  2. public static void main(String[] args) throws IOException {
  3. File f1 = new File("C:\\Windows");
  4. File f2 = new File("C:\\Windows\\notepad.exe");
  5. //是文件?
  6. System.out.println(f1.isFile()); //false
  7. //是目录?
  8. System.out.println(f1.isDirectory()); //false
  9. System.out.println(f2.isFile());//false
  10. System.out.println(f2.isDirectory());//false
  11. }
  12. }

File对象获取到一个文件时,还可以进一步判断文件的权限和大小:

  • boolean canRead():是否可读;
  • boolean canWrite():是否可写;
  • boolean canExecute():是否可执行;
  • long length():文件字节大小。

对目录而言,是否可执行表示能否列出它包含的文件和子目录。

2.创建和删除文件

当File对象表示一个文件时,可以通过createNewFile()创建一个新文件,用delete()删除该文件:

  1. File file = new File("/path/to/file");
  2. file.createNewFile()
  3. file.delete()

有些时候,程序需要读写一些临时文件,File对象提供了createTempFile()来创建一个临时文件,以及deleteOnExit()在JVM退出时自动删除该文件。

  1. File f = File.createTempFile("tmp-", ".txt"); // 提供临时文件的前缀和后缀
  2. f.deleteOnExit(); // JVM退出时自动删除
  3. System.out.println(f.isFile()); //true
  4. System.out.println(f.getAbsolutePath()); ///tmp/tmp-11900775370391459620.txt

3.遍历文件和目录

当File对象表示一个目录时,可以使用list()listFiles()列出目录下的文件和子目录名。listFiles()提供了一系列重载方法,可以过滤不想要的文件和目录:

  1. public class Main {
  2. public static void main(String[] args) throws IOException {
  3. File f = new File("C:\\Windows");
  4. File[] fs1 = f.listFiles(); // 列出所有文件和子目录
  5. printFiles(fs1);
  6. File[] fs2 = f.listFiles(new FilenameFilter() { // 仅列出.exe文件
  7. public boolean accept(File dir, String name) {
  8. return name.endsWith(".exe"); // 返回true表示接受该文件
  9. }
  10. });
  11. printFiles(fs2);
  12. }
  13. static void printFiles(File[] files) {
  14. System.out.println("==========");
  15. if (files != null) {
  16. for (File f : files) {
  17. System.out.println(f);
  18. }
  19. }
  20. System.out.println("==========");
  21. }
  22. }

和文件操作类似,File对象如果表示一个目录,可以通过以下方法创建和删除目录:

  • boolean mkdir():创建当前File对象表示的目录;
  • boolean mkdirs():创建当前File对象表示的目录,并在必要时将不存在的父目录也创建出来;
  • boolean delete():删除当前File对象表示的目录,当前目录必须为空才能删除成功。

    4.Path

    Java标准库还提供了一个Path对象,它位于java.nio.file包。Path对象和File对象类似,但操作更加简单:

    1. Path p1 = Paths.get(".", "project", "study"); // 构造一个Path对象
    2. System.out.println(p1);
    3. Path p2 = p1.toAbsolutePath(); // 转换为绝对路径
    4. System.out.println(p2);
    5. Path p3 = p2.normalize(); // 转换为规范路径
    6. System.out.println(p3);
    7. File f = p3.toFile(); // 转换为File对象
    8. System.out.println(f);
    9. for (Path p : Paths.get("..").toAbsolutePath()) { // 可以直接遍历Path
    10. System.out.println(" " + p);
    11. }

    如果需要对目录进行复杂的拼接、遍历等操作,使用Path对象更方便。
    小结:
    Java标准库的java.io.File对象表示一个文件或者目录:

  • 创建File对象本身不涉及IO操作;

  • 可以获取路径/绝对路径/规范路径:getPath()/getAbsolutePath()/getCanonicalPath()
  • 可以获取目录的文件和子目录:list()/listFiles()
  • 可以创建或删除文件和目录。

    5.练习

    请利用File对象列出指定目录下的所有子目录和文件,并按层次打印。
    例如,输出:
    1. Documents/
    2. word/
    3. 1.docx
    4. 2.docx
    5. work/
    6. abc.doc
    7. ppt/
    8. other/
    如果不指定参数,则使用当前目录,如果指定参数,则使用指定目录。

    6.总结

    6.1 文件句柄方法

    1. File file = new File("c:/qf/abc/小姐姐.txt");
    2. //操作
    3. file.createNewFile();// 创建文件
    4. file.getParentFile();// 获取到上级目录句柄
    5. file.getParent(); //获取到上级目录字符串
    6. file.mkdir();// 创建文件夹
    7. file.mkdirs();// 创建文件夹(多级文件夹,推荐!!!)
    8. file.renameTo(new File("新名字"));// 重命名
    9. file.delete();// 删除文件
    10. // 查看
    11. System.out.println(file.exists()); // 判断文件是否存在
    12. System.out.println(file.isAbsolute()); // 是否是绝对路径
    13. System.out.println(file.isDirectory()); // 是否是文件夹
    14. System.out.println(file.isFile()); // 是否是文件
    15. System.out.println(file.getName()); //获取文件名字
    16. System.out.println(file.length()); // 文件大小

    6.2 创建文件的步骤

    1. File file = new File("c:/qf/abc/小姐姐.txt");
    2. // 首先, 判断文件夹是否存在
    3. File parentFile = file.getParentFile();
    4. if(!parentFile.exists() || parentFile.isFile() ){
    5. parentFile.mkdirs();// 创建上级目录
    6. }
    7. file.createNewFile(); // 创建文件

    二、基本IO流

    上一节, 我们可以创建文件和删除文件, 也就是说, 我们可以对文件进行操作了. 但是文件的内容还没办法读取和写入. 本节, 咱们就说说这个文件怎么读取和写入. 在java中读写文件使用IO流来完成.
    流的分类:
  1. 按照读写内容的单位来讲, 分为字节流和字符流
  2. 按照读写的方向来讲, 分为输入流和输出流
  3. 按照流的功能不同, 分为节点流和处理流

懵逼了吧. 哈哈. 别担心. 我们一个一个看.
1.站在程序的角度. 从文件里读取内容,这个叫输入流,向文件里写入内容叫输出流。
2.对于英文而言我们之前说过, 英文是ascii的范畴。一个ascii是一个字节。所以字节流一次读取的是一个字节,这样的流是可以处理英文的,但是如果是中文就不行了,中文必须用字符流。
3.节点流主要指的是直接插在文件上的流,在文件上开辟一个节点来读取内容。而处理流是用来处理其他流的,就好比我们家的自来水净化器,它是套在我们正常的自来水管道上的。我们从净化器接的水是被净化器处理过的,一样. 从处理流获取到的数据是经过处理的。
接下来,我们来说说流的家族体系。不管是什么流,最终都是基于这个体系产生的。
流一共有4个祖宗.

输入 输出
字节流 InputStream OutputStream
字符流 Reader Writer

万变不离其宗, 所有的流在使用上基本上都是从这几个流过来的. 但是很不幸, 这几个流都是抽象类. 我们不能直接创建这几个类的对象. 所以, 我们必须学习他们的子类间接的来学习流。
节点流:文件流

  1. FileInputStream
  2. FileOutputStream
  3. FileReader
  4. FileWriter

    1.文件字节输入流FileInputStream

    1. public static void main(String[] args) {
    2. try {
    3. //1.以字节流形式打开文件
    4. InputStream fis = new FileInputStream(new File("aa.txt"));
    5. //每次读取一个字节
    6. // int b = fis.read(); //每次读取1个字节
    7. // System.out.println(b); //第1个字节 在ASCII中数字表示
    8. // System.out.println((char)b);
    9. // int b2 = fis.read(); //每次读取2个字节
    10. // System.out.println(b2); //第2个字节 在ASCII中数字表示
    11. // System.out.println((char)b2);
    12. //2.读取一定长度字节,read() 传入一定长度的字节数组
    13. byte[] bs = new byte[1024];
    14. int len=0;
    15. while ((len = fis.read(bs)) != -1){ // 当文件内容读完之后 fis.read() == -1
    16. System.out.println(new String(bs,0,len)); // 字节数组中不全是从文件里读取到的内容(如果文件内容少于1024 剩余位置用null占位)
    17. }
    18. //3.关闭文件
    19. fis.close();
    20. } catch (FileNotFoundException e) {
    21. e.printStackTrace();
    22. } catch (IOException e) {
    23. e.printStackTrace();
    24. }
    25. }

    2.文件字节输出流FileOutputStream

    构造方法

    7、File类与I/O流 - 图1

    成员方法

    1. public static void main(String[] args) {
    2. try {
    3. //准备工作-创建文件
    4. File fw = new File("./notebooks/aa.txt");
    5. File parentFile = fw.getParentFile();
    6. if(!parentFile.exists()){
    7. parentFile.mkdirs();
    8. }
    9. fw.createNewFile();
    10. //1.以字节流形式打开文件
    11. OutputStream fos = new FileOutputStream(fw);
    12. //OutputStream fos = new FileOutputStream("./1.jpg"); //可以直接传入文件路径
    13. //2.读取一定长度字节,read() 传入一定长度的字节数组
    14. byte[] bs = "我是中国人,黄皮肤,棕色眼睛,我是龙的传人".getBytes();
    15. fos.write(bs);
    16. //3.写入文件
    17. fos.flush();
    18. fos.close();
    19. } catch (FileNotFoundException e) {
    20. e.printStackTrace();
    21. } catch (IOException e) {
    22. e.printStackTrace();
    23. }
    24. }
    我们发现, 中文可以写出去. 原因是, 我们按照字节的形式写出去. 到了文件里. 又被拼凑成正常的文字了. 所以可以看见中文. 但是read就不行了. read读到的是字节. 对于GBK而言, 你每次读取的其实就是半个字. 没办法显示的. 先更要读取中文. 必须用字符流

    3.文件字符输入流FileReader

    构造方法

  • FileReader(File file) 创建一个新的 FileReader ,给出要读取的 File对象。
  • FileReader(String fileName) 创建一个新的 FileReader ,给定要读取的文件名称。

    成员方法

  • close() 关闭流并释放与之相关联的任何系统资源

  • int len = read() 读一个字符
  • int len = read(char[] cbuf, int offset, int length) 将字符读入数组的一部分。
    1. public static void main(String[] args) {
    2. try {
    3. //1.以字符形式打开文件
    4. Reader file_reader = new FileReader(new File("aa.txt"));
    5. //2.读取一定长度字节,read() 传入一定长度的字符数组
    6. char[] temp = new char[1024];
    7. int len=0;
    8. while ((len = file_reader.read(temp)) != -1){ // 当文件内容读完之后 fis.read() == -1
    9. System.out.println(new String(temp,0,len)); // 字符流能读取中文
    10. }
    11. //3.关闭文件
    12. file_reader.close();
    13. } catch (FileNotFoundException e) {
    14. e.printStackTrace();
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. }
    18. }
    聪明的你应该已经发现了. 这个Reader和InputStream的代码很像. 除了byte和char数组的区别. 其他写法一模一样. 这就对了. 这两个功能本来就是一样的. 区别就是单位的不同. 所以. 关于IO流的代码. 记住一份足以. 其他的照葫芦画瓢就行了.

    4.文件字符输出流FileWriter

    1. public static void main(String[] args) {
    2. try {
    3. //准备工作-创建文件
    4. File fw = new File("./notebooks/aa.txt");
    5. File parentFile = fw.getParentFile();
    6. if(!parentFile.exists()){
    7. parentFile.mkdirs();
    8. }
    9. fw.createNewFile();
    10. //1.以字节流形式打开文件
    11. Writer file_writer = new FileWriter(fw,true); //append 追加写入
    12. //2.直接写入字符串
    13. file_writer.write("\r\n我是下一行数据追加!"); //换行
    14. //3.写入文件
    15. file_writer.flush();
    16. file_writer.close();
    17. } catch (FileNotFoundException e) {
    18. e.printStackTrace();
    19. } catch (IOException e) {
    20. e.printStackTrace();
    21. }
    22. }
    练习:使用IO流, 把一张图片从aa文件夹复制到bb文件夹(不存在就先创建).(附加思考: 如果是剪切呢?)
    1. public static void main(String[] args) throws Exception {
    2. /*使用IO流, 把一张图片从aa文件夹复制到bb文件夹(不存在就先创建).(附加思考: 如果是剪切呢?)*/
    3. File f_source = new File("./aa/meinv.jpg");
    4. InputStream fis = new FileInputStream(f_source);
    5. //写byte
    6. File file = new File("./bb/new_meinv.jpg");
    7. File parentFile = file.getParentFile();
    8. if(!parentFile.exists()){
    9. parentFile.mkdirs();
    10. }
    11. file.createNewFile();
    12. OutputStream fos = new FileOutputStream(file);
    13. byte[] bs = new byte[1024];
    14. int len = 0;
    15. while ((len = fis.read(bs))!= -1){
    16. fos.write(bs,0,len);
    17. }
    18. //剪切也简单-拷贝完之后直接删除fis即可
    19. f_source.delete();
    20. fos.flush();
    21. fos.close();
    22. System.out.println("拷贝完成!");
    23. }
    总结:
    1.文档(含中英文)操作,使用字符流FileReader-Reader FileWriter-Writer,可以直接读写字符串;
    2.音视频/压缩文件等操作,使用字节流FileInputStream-InputStream FileOutputStream-OutStreamread(bs) write(bs,0,len)需要传入字节长度数组;

    三、处理流

    1.概念:

    上节课我们还学了文件流(即节点流):FileInputStream, FileOutputStream, FileReader, FileWriter
    以上流都是节点流,这节课我们来探索一下处理流。
    前面我们说过, 从文件中读取内容相当于在文件上插了一个管子,在管子上进行读写数据,就好比我们喝奶茶的时候插根管子从管子里喝。
    7、File类与I/O流 - 图2
    我们可以在这个管道的基础上进一步的进行处理,处理管道的叫处理流。说白了. 在管道上再套一根管道.
    7、File类与I/O流 - 图3
    此时读取和写入的内容就会自动被处理流给处理一下.
    处理流的分类:
  1. 缓冲流
  2. 转换流
  3. 对象流

    2.缓冲流BufferedReader

    | | 输入 | 输出 | | —- | —- | —- | | 字节流 | BufferedInputStream | BufferedOutputStream | | 字符流 | BufferedReader | BufferedWriter |

发现规律了么? 还是4个,没错你把最原始的那四个记住了. 基本上流也就掌握了.
7、File类与I/O流 - 图4
我们发现, BufferedInputStream除了在创建对象的时候多套弄了一层以外, 好像没有什么实质的进展. 不好用. 对于BufferedOutputStream其实也是一样的。所以这两个类一般不怎么使用,关键在BufferReader

  1. public static void main(String[] args) throws Exception {
  2. BufferedReader bf = new BufferedReader(new FileReader(new File("麻花藤.txt")));
  3. // String str = bf.readLine(); // 一次读取一行内容. 爽啊. 终于不用再管神马byte[] 了
  4. // System.out.println(str);
  5. String str = "";
  6. while((str = bf.readLine())!=null){ // 读取文本文件最爽的一种写法
  7. System.out.println(str);
  8. }
  9. }

3.转换流

我们已经可以使用流的基本操作来完成读写任务了. 但是, 还有一个事情我们需要解决. 在很多情况下. 我们是拿不到字符流的。就比如System.in. 这个就是一个字节流。它默认连接着控制台,那我们如何从System.in中读取到数据呢? 我么可以使用转换流,把System.in这种字节流转换成字符流,这样读取数据的时候就方便很多。
转换流有两个, 一个是InputStreamReader, 另一个是OutputStreamWriter

  1. BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  2. System.out.println(br.readLine());

运行起来, 感觉和Scanner是一样的.
同理. System.out是一个输出流. 我们就可以把System.out转换成Writer

  1. BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
  2. bw.write("我的天啊");
  3. bw.newLine(); //换行
  4. bw.flush();
  5. bw.close();
  6. System.out.println("hahaaha!"); //无法显示

注意, System.out不可以关闭,关闭了 后面我们就不能再打印了
7、File类与I/O流 - 图5

4.对象流

在java中, 万事万物皆为对象, 那我们能不能把一个对象写入到文件里呢? 答案是肯定的. 如何操作呢? 我们需要用到对象流ObjectStream

  1. public static void main(String[] args) throws Exception {
  2. //创建对象
  3. Teacher t = new Teacher(1, "蔡徐坤", 88);
  4. // 创建对象输出流
  5. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("teacher.dat")));
  6. oos.writeObject(t); // 把一个对象写入到一个文件中
  7. oos.flush();
  8. oos.close();
  9. }

代码写完了. 运行, 发现报错了. 为什么呢? 先看看这个错误是什么?

Exception in thread “main” java.io.NotSerializableException: com.xyq.io.Teacher at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1185) at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:349) at com.xyq.io.Test.main(Test.java:14)

NotSerializableException: 表示没有开启序列化功能。什么是序列化呢? 我们知道我们创建的对象是保存在内存里的, 数据内存的数据, 而内存和硬盘里的数据保存方式是不一样的. 对于硬盘而言, 只有两种格式, 要么是字符, 要么是字节. 就这两种保存方式, 所以, 我们想要把对象写入到硬盘, 就必须把一个对象转换成字节或者字符。
对于一个对象而言, 转换成字符很显然不是很合适, 那把一个对象转换成字节的过程被称之为序列化, 并且, 序列化的内容将来还可能会被反序列化回我们的对象. JDK为每一个类都准备了序列化功能. 但是由于序列化太过于消耗资源. 默认都是不开启的. 如果想要开启该功能. 需要让你的类实现Serializable接口,这是一个标志性接口, 并没有方法在里面(即不需要重写方法),当JDK发现你的类实现了这个接口了,就意味着你要序列化了。所以. 大家以后只要看到了这个错误. 直接实现一个接口即可。

  1. public class Person implements Serializable {

测试通过…来, 看看这个文件里写的是什么把
7、File类与I/O流 - 图6
我们发现这个文件里好多都是乱码. 隐隐约约能看到蔡徐坤。所以. 记住, 这个文件不是给人看的. 是给程序用的. 那程序怎么用呢? 很简单. 你能写, 就一定能读. 对吧. 写用ObjectOutputStream. 那读一定是ObjectInputStream
Person.java

  1. public class Person implements Serializable {
  2. private String name;
  3. private int age;
  4. private String gender;
  5. public Person(String name, int age, String gender) {
  6. this.name = name;
  7. this.age = age;
  8. this.gender = gender;
  9. }
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public int getAge() {
  17. return age;
  18. }
  19. public void setAge(int age) {
  20. this.age = age;
  21. }
  22. public String getGender() {
  23. return gender;
  24. }
  25. public void setGender(String gender) {
  26. this.gender = gender;
  27. }
  28. }

对象写入:

  1. public static void main(String[] args) throws Exception {
  2. Person p1 = new Person("刘德华",18,"男");
  3. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"));
  4. oos.writeObject(p1);
  5. oos.flush();
  6. oos.close();
  7. }

对象读取:

  1. public static void main(String[] args) throws Exception {
  2. ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("person.dat")));
  3. Object obj = ois.readObject();
  4. Person p1 = (Person) obj;
  5. System.out.println(p1.getName()); //刘德华
  6. ois.close();
  7. }

四、文件修改

1.替换txt文件关键字

把文件”唐诗三百首.txt”文件中所有的李白替换成李太白.

  1. 唐诗三百首
  2. 1. 静夜思, 李白, 窗前明月光, 疑是地上霜, 举头望明月, 低头思故乡
  3. 2. 望庐山瀑布, 李白, 日照香炉生紫烟, 遥看瀑布挂前川, 飞流直下三千尺, 疑是银河落九天.
  4. 3. 早发白帝城, 李白, 朝辞白帝彩云, 千里江陵一日还, 两岸猿声啼不住, 轻舟已过万重山.

结果:

  1. 唐诗三百首
  2. 1. 静夜思, 李太白, 窗前明月光, 疑是地上霜, 举头望明月, 低头思故乡
  3. 2. 望庐山瀑布, 李太白, 日照香炉生紫烟, 遥看瀑布挂前川, 飞流直下三千尺, 疑是银河落九天.
  4. 3. 早发白帝城, 李太白, 朝辞白帝彩云, 千里江陵一日还, 两岸猿声啼不住, 轻舟已过万重山.

用咱们现在所知道的知识点还无法直接解决. 为什么会这样呢? 我们知道硬盘是一个连续的存储结构. 假设被写入到磁盘的是这样的:
7、File类与I/O流 - 图7
此时我想把”叫”改成”朋友”, 那么假设可以直接修改. 就会变成这样
7、File类与I/O流 - 图8
所以, 想要实现文件修改功能. 不可以在原有的基础上进行修改. 那怎么办? 我们可以准备一个文件的副本. 把新内容写到副本文件里. 写完之后, 把副本变成原文件. 并把源文件删除. 如果这个动作够快. 大家看到的就是文件修改的效果. 我们平时使用的word就是这样操作的. 所以我们每次操作word文档的时候都能看到一个文件副本出现. 一保存, 文件副本不见了. 其实是把文件副本变成了源文件

  1. public static void main(String[] args) throws Exception {
  2. File f1 = new File("./唐诗三百首.txt");
  3. File f2 = new File("./副本_唐诗三百首.txt");
  4. BufferedReader br = new BufferedReader(new FileReader(f1));
  5. BufferedWriter bw = new BufferedWriter(new FileWriter(f2));
  6. String line = "";
  7. while ((line = br.readLine()) != null){
  8. line = line.replace("李太白","【李太白】");
  9. bw.write(line); //写到新文件
  10. bw.newLine(); //换行
  11. }
  12. br.close();
  13. bw.flush();
  14. bw.close();
  15. //删除源文件
  16. f1.delete();
  17. f2.renameTo(f1);
  18. }

7、File类与I/O流 - 图9

2.计算水果价钱

再来看另一个案例,读取文件中的水果信息. 计算水果的总价(价格x库存). 并写入到文件中
fruit.txt:

  1. 名称_价格_库存
  2. 香蕉_3.33_20
  3. 苹果_1.25_10
  4. 橘子_1.33_40

结果:

  1. 名称_价格_库存_总价
  2. 香蕉_3.33_20_66.60
  3. 苹果_1.25_10_12.50
  4. 橘子_1.00_40_40.00

代码如下:

  1. public static void main(String[] args) throws Exception {
  2. File file_source = new File("fruit.txt");
  3. BufferedReader br = new BufferedReader(new FileReader(file_source));
  4. File file_ret = new File("temp_fruit.txt");
  5. BufferedWriter bw = new BufferedWriter(new FileWriter(file_ret));
  6. DecimalFormat df = new DecimalFormat(".00");
  7. //读第一行数据
  8. String title = br.readLine();
  9. bw.write(title+"_总价");
  10. bw.newLine();
  11. String line = "";
  12. while ((line = br.readLine())!=null){
  13. String[] price_num = line.split("_");
  14. Double price = Double.parseDouble(price_num[1]);
  15. Double num = Double.parseDouble(price_num[2]);
  16. Double total = price*num;
  17. String totalStr = df.format(total);
  18. bw.write(line+="_"+totalStr);
  19. bw.newLine();
  20. }
  21. br.close();
  22. bw.flush();
  23. bw.close();
  24. //删除源文件并重命名新文件
  25. file_source.delete();
  26. file_ret.renameTo(file_source);
  27. }

7、File类与I/O流 - 图10