JavaEE-文件和IO(二)

Source

2.2 文件内容相关的操作

  1. 打开文件
  2. 读文件
  3. 写文件
  4. 关闭文件

针对文件内容的读写,java标准库提供了一组类~
首先按照文件的内容,分为两个系列

  1. 字节流对象,针对二进制文件,是以字节为单位进行读写的,读:InputStream,写:OutputStream。
  2. 字符流对象,针对文本文件,是以字符为单位进行读写的,读:Reader,写:Writer。

InputStream
在这里插入图片描述
在这里插入图片描述
read提供了三个版本的重载

  1. 无参版本:一次读一个字节
  2. 一个参数版本:一次读若干个字节,把读的结果放到参数指定的数组中,返回值就是读到的字节数
  3. 三个参数版本:一次读若干个字节,把读的结果放到参数指定的数组中,返回值就是读到的字节数,不是从数组的起始位置放置,而是从中间位置放置(off这个下标的位置)len表示最多能放多少个元素(字节)

在这里插入图片描述 在这里插入图片描述
IO操作失败的可能性是非常大的,另外硬盘也容易出现“坏道”

package file;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

@SuppressWarnings({
    
      "all"})
public class Demo8 {
    
      
    public static void main(String[] args) {
    
      
        // 构造方法中需要指定打开文件的路径
        try {
    
      
            // 1. 创建对象,同时也是在打开文件
            InputStream inputStream = new FileInputStream("d://tst.txt");
            // 2. 尝试一个一个字节的读,把整个文件读完
            while (true) {
    
      
                int b = inputStream.read();
                if (b == -1)
                    break;
                System.out.println(b);
            }
            // 3. 读完之后要记得关闭文件,释放资源
            inputStream.close();
        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }
    }
}

在这里插入图片描述
在这里插入图片描述
更好的做法是把close放到finally里面
改进之后的代码

package file;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

@SuppressWarnings({
    
      "all"})
public class Demo8 {
    
      
    public static void main(String[] args) {
    
      
        // 构造方法中需要指定打开文件的路径
        InputStream inputStream = null;
        try {
    
      
            // 1. 创建对象,同时也是在打开文件
            inputStream = new FileInputStream("d://tst.txt");
            // 2. 尝试一个一个字节的读,把整个文件读完
            while (true) {
    
      
                int b = inputStream.read();
                if (b == -1)
                    break;
                System.out.println(b);
            }

        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        } finally {
    
      
            // 3. 读完之后要记得关闭文件,释放资源
            try {
    
      
                inputStream.close();
            } catch (IOException e) {
    
      
                throw new RuntimeException(e);
            }
        }
    }
}

try (InputStream inputStream = new FileInputStream("d:/test.txt");){
    
      
            while (true) {
    
      
                int b = inputStream.read();
                if (b == -1) {
    
      
                    break;
                }
                System.out.println(b);
            }
        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }

在这里插入图片描述
在这里插入图片描述

try (InputStream inputStream = new FileInputStream("d:/test.txt")){
    
      
            // 一次读取若干个字符
            while (true) {
    
      
                byte[] buffer = new byte[1024];
                int len = inputStream.read(buffer);
                if (len == -1) {
    
      
                    // 如果返回-1 就读完了
                    break;
                }
                for (int i = 0; i < len; i++) {
    
      
                    System.out.println(buffer[i]);
                }
            }

        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }

在这里插入图片描述
OutputStream
在这里插入图片描述

public static void main(String[] args) {
    
      
        try (OutputStream outputStream = new FileOutputStream("d:/test.txt")) {
    
      
//            outputStream.write(97);
//            outputStream.write(98);
//            outputStream.write(99);
            byte[] buffer = new byte[]{
    
      97, 98, 99};
            outputStream.write(buffer);
        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }
    }

在这里插入图片描述

package file;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

@SuppressWarnings({
    
      "all"})
public class Demo10 {
    
      
    public static void main(String[] args) {
    
      
        try (Reader reader = new FileReader("d/test.txt")){
    
      
            // 按照字符来读
            while (true) {
    
      
                char[] buffer = new char[1024];
                int len = reader.read(buffer);
                if (len == -1) {
    
      
                    break;
                }
                for (int i = 0; i < len; i++) {
    
      
                    System.out.println(buffer[i]);
                }
                String s = new String(buffer, 0, len);
                System.out.println(s);
            }
        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }
    }
}

package file;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

// 按照字符来写
@SuppressWarnings({
    
      "all"})
public class Demo11 {
    
      
    public static void main(String[] args) {
    
      
        try (Writer writer = new FileWriter("d:?test.txt")){
    
      
            writer.write("xyz");
        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }
    }
}

三、文件操作案例

3.1 案例一

扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要
删除该文件

用户输入一个目录~
再输入一个要删除的文件名~

package file;

import java.io.File;
import java.io.IOException;
import java.util.Scanner;

// 案例1 查找文件并删除
@SuppressWarnings({
    
      "all"})
public class Demo12 {
    
      
    public static void main(String[] args) {
    
      
        // 1. 先输入要扫描的目录,以及要删除的文件
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要扫描的路径:");
        String rootDirPath = scanner.next();
        System.out.println("请输入要删除的文件名");
        String toDeleteName = scanner.next();
        File rootDir = new File(rootDirPath);
        if (!rootDir.isDirectory()) {
    
      
            System.out.println("输入的要扫描的路径有误!");
            return;
        }
        // 2. 遍历目录,把指定目录中的所有文件都遍历一遍,从而要找到删除的文件
        //    通过这个方法来实现递归遍历并删除的操作
        scanDir(rootDir, toDeleteName);
    }

    private static void scanDir(File rootDir, String toDeleteName) {
    
      
        // 1. 先列出 rootDir 中都有哪些内存
        File[] files = rootDir.listFiles();
        if (files == null) {
    
      
            // rootDir 是一个空目录
            return;
        }
        // 2. 遍历当前列出的这些内容,如果是普通文件,就检测文件名是否是要删除的文件
        //    如果是目录,就递归的进行遍历
        for (File f : files) {
    
      
            if (f.isFile()) {
    
      
                // 普通文件的情况
                if (f.getName().contains(toDeleteName)) {
    
      
                    // 不要求名字完全一样,只要文件名中包含了关键字即可删除
                    // 就进行删除操作
                    deleteFile(f);
                }
            } else if (f.isDirectory()) {
    
      
                // 目录就递归的进行遍历
                scanDir(f, toDeleteName);
            }
        }
    }

    private static void deleteFile(File f) {
    
      
        try {
    
      
            System.out.println(f.getCanonicalPath() + "确认要删除吗?");
            Scanner scanner = new Scanner(System.in);
            String choice = scanner.next();
            if (choice.equals("Y") || choice.equals("y")) {
    
      
                f.delete();
                System.out.println("文件删除成功!");
            } else {
    
      
                System.out.println("文件取消删除!");
            }
        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }
    }
}

3.2 案例二

进行普通文件的复制

需要让用户指定两个文件路径
一个是原路径(被复制的文件)
一个是目标路径(复制之后生成的文件)
打开源路径的文件,读取里面的内容,并写入目标文件

package file;


import jdk.internal.util.xml.impl.Input;

import java.io.*;
import java.util.Scanner;

@SuppressWarnings({
    
      "all"})
public class Demo13 {
    
      
    public static void main(String[] args) {
    
      
        // 1. 输入两个路径
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要拷贝的源路径:");
        String src = scanner.next();
        System.out.println("请输入要拷贝的目标路径:");
        String dest = scanner.next();
        File srcFile = new File(src);
        if (!srcFile.isFile()) {
    
      
            System.out.println("输入的源路径不正确!");
            return;
        }
        // 此处不太需要检查目标文件是否存在,OutputStream写文件的时候能够自动创建不存在的文件
        // 2. 读取源文件,拷贝到目标文件中
        try (InputStream inputStream = new FileInputStream(src)) {
    
      
            try (OutputStream outputStream = new FileOutputStream(dest)){
    
      
                // 把inputStream中的数据写到OutputStream
                byte[] buffer = new byte[1024];
                while (true) {
    
      
                    int len = inputStream.read(buffer);
                    if (len == -1) {
    
      
                        break;
                    }
                    // 写入的时候,不能把整个buffer写进去,可能只有一部分是有效数据
                    outputStream.write(buffer, 0 , len);
                }
            }
        } catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }
    }
}

3.3 案例三

扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
注意:我们现在的方案性能较差,所以尽量不要在太复杂的目录下或者大文件下实验

进行文件内容的查找
先输入一个路径
再输入一个要查找文件内容的”关键字“

递归遍历文件,找到看哪个文件里的内容包含了关键字,就把对应的文件路径打印出来

package file;


import java.io.*;
import java.util.Scanner;

@SuppressWarnings({
    
      "all"})
public class Demo14 {
    
      
    public static void main(String[] args) throws IOException {
    
      
        // 1. 输入要扫描的文件路径
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要扫描的路径:");
        String rootDirPath = scanner.next();
        System.out.println("请输入要查询的关键词:");
        String word = scanner.next();
        File rootDir = new File(rootDirPath);
        if (!rootDir.isDirectory()) {
    
      
            System.out.println("输入的路径非法!");
            return;
        }
        // 2. 递归遍历
        scanDir(rootDir, word);
    }

    private static void scanDir(File rootDir, String word) throws IOException {
    
      
        // 1. 先列出 rootDir 中都有哪些内容
        File[] files = rootDir.listFiles();
        if (files == null) {
    
      
            return;
        }
        // 2. 遍历每个元素,针对普通文件和目录进行分别处理
        for (File f : files) {
    
      
            if (f.isFile()) {
    
      
                // 针对文件进行内容查找
                if (containsWord(f, word)) {
    
      
                    System.out.println(f.getCanonicalPath());
                }
            } else if (f.isDirectory()) {
    
      
                // 针对目录进行递归
                scanDir(f, word);
            }
        }
    }

    private static boolean containsWord(File f, String word) {
    
      
        // 写代码,慎重使用缩写
        StringBuilder stringBuilder = new StringBuilder();
        // 把 f 中的内容都读出来,放到一个StringBuilder中
        try (Reader reader = new FileReader(f)){
    
      
            char[] buffer = new char[1024];
            while (true) {
    
      
               int len = reader.read(buffer);
               if (len == -1) {
    
      
                   break;
               }
               // 把这一段读到的结果,放到StringBuilder中
                stringBuilder.append(buffer, 0, len);
            }
        }  catch (IOException e) {
    
      
            throw new RuntimeException(e);
        }
        // indexOf 返回的是子串的下标,如果word 再stringBuilder中不存在就返回-1
        return stringBuilder.indexOf(word) != -1;
    }
}