【Java】使用FileInputStream和FileOutputStream进行文件操作(最后有小案例)

读完本文你能学会使用FileInputStream和FileOutputStream进行文件内容的输入输出。

在本文的最后有小案例:在指定目录下递归查询该目录下的所有子文件,进行文件的复制等,这些操作都是使用FileInputStream和FileOutputStream类进行文件操作完成的

  • 使用File类来打开一个文件,并可以使用API打印出文件的信息
// 获得文件的相关信息
public static void main(String[] args) throws IOException {
    // pathname:可以是绝对路径也可以是相对路径
    // 如果直接写文件名,默认是相对路径
    File file = new File("./test.txt");
    System.out.println(file.getName());
    System.out.println(file.getParent());
    System.out.println(file.getPath());
    System.out.println(file.getAbsolutePath());
    System.out.println(file.getCanonicalPath());
}
  • 使用File类创建文件
  • 使用File类创建单级/多级目录,删除单级/多级目录(删除多级目录以及目录下的所有文件)
// 创建普通文件和文件夹,并且删除普通文件和文件夹
public static void main(String[] args) throws IOException, InterruptedException {
    // test.txt文件不存在
    File file = new File("test.txt");
    // 创建文件,并立刻删除(为了效果显示中间使用thread进行了休眠)
    file.createNewFile(); // 创建文件
    Thread.sleep(3000);
    file.delete(); // 删
    // 创建文件,并在退出的时候删除该文件
    file.createNewFile(); // 创建文件
    Thread.sleep(3000);
    file.deleteOnExit(); // 不立即删除文件,而是在程序退出的时候删除
    Thread.sleep(300
    // 创建目录
    File dir = new File("./dir");
    dir.mkdir(); // 使用mkdir只能创建单级目录
    System.out.println(dir.isDirectory());
    Thread.sleep(1000);
    dir.deleteOnExit(); // 不立即删除文件夹,而是在程序退出的时
    File dirs = new File("./dir1/dir2/dir3");
    dirs.mkdirs(); // 使用mkdirs可以创建多级目录
    System.out.println(dirs.isDirectory());
    // 注意delete不能删除多级目录,只能通过递归的方式来删除多级目录
    // 调用deleteDir函数
    deleteDir("./dir1");
    Thread.sleep(1000);
}
public static void deleteDir(String basePath) {
    File file = new File(basePath);
    if (file.isFile()) {
        file.delete();
    }
    String[] dir = file.list();
    for (String d : dir) {
        deleteDir(basePath + "/" + d);
    }
    file.delete();
}
  • 显示目录下的所有文件(如果目录下有目录,不显示子目录下的文件)
  • 显示目录下的所有文件,包括子目录下的文件
// 显示所有文件列表
public static List<String> files = new ArrayList<>(); // 文件列表
public static void main(String[] args) {
    // 打印当前目录(.)下的所有文件
    File file = new File(".");
    String[] list = file.list(); // 使用list()方法可以返回当前目录下的所有文件
    System.out.println(Arrays.toString(list)); // 将String[]数组转换成Str
    // 打印当前目录下的所有文件及其子文件
    showAllFile(".");
    for (String f : files) {
        System.out.println(f);
    }

public static void showAllFile(String basePath) {
    // 如果是普通文件直接打印文件名,如果是目录就使用list()列出当前目录下的所有文件
    File file = new File(basePath);
    if (file.isFile()) {
        files.add(file.getName());
        return;
    }
    // 这里只考虑目录文件
    String[] dir = file.list();
    for (String s : dir) {
        showAllFile(basePath + "/" + s);
    }
}
  • 文件的剪贴(移动)
// 文件的移动(文件的剪贴)
public static void main(String[] args) throws IOException {
    // 在当前目录下创建一个test.txt文件,并将这个目录移动到tmp目录下
    File file = new File("./test.txt");
    file.createNewFile();
    File dir = new File("./tmp");
    dir.mkdir();
    File newFile = new File("./tmp/test.txt");
    file.renameTo(newFile); // 将file文件改名成newFile文件就相当于file文件剪贴到tmp目录下
}
  • 使用文件输入流FileInputStream进行文件输入的三种方式
// 文件的输入输出
public static void main(String[] args) throws IOException { // 对于异常的处理直接throws
    // 创建一个FileInputStream文件流
    /第一种写法/
    InputStream inputStream = new FileInputStream("./test.txt");
    // 方法一:使用输入文件流中的read()可以将文件的内容进行读取
    while (true) {
        int b = inputStream.read();
        if (b == -1) break;
        System.out.printf("%c", b);
    }
    inputStream.close(); // 记得一定要关闭输入文件流
    /第二种写法/
    // 方法二:使用try catch finally更科学地调用close方法
    InputStream inputStream1 = null;
    try {
        inputStream1 = new FileInputStream("./test.txt");
        while (true){
            int b = inputStream1.read();
            if (b == -1) break;
            System.out.printf("%c", b);
        }
    } catch(IOException e) {
        e.printStackTrace();
    } finally {
        try {
            inputStream1.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /第三种写法
    // 方法三:try with resources语法,在try的()中new一个FileInputStream对象
    // 在文件不用的时候,自动调用close方法,这样就不用手动调用close()了
    try (InputStream inputStream2 = new FileInputStream("./test.txt")) {
        while (true) {
            int b = inputStream2.read();
            if (b == -1) break;
            System.out.printf("%c", b);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 使用使用FileInputStream将文件内容读到缓冲区中
public static void main(String[] args) {
    // 使用byte[]作为缓冲区进行文件读取
    // 使用try with resouce创建一个FileInputstream
    try (InputStream inputStream = new FileInputStream("./test.txt")) {
        byte[] buffer = new byte[1024];
        while (true) {
            // 将文件内容放入buffer缓冲区中
            int len = inputStream.read(buffer);
            if (len == -1) break;
			// 不同的编码格式下,一个字符所用的字节数不同,所以不能直接按%c的方式进行读取,否则有可能出现乱码
            for (int i = 0; i < len; i ++) {
                System.out.printf("%c", buffer[i]);
            }
              for (int i = 0; i < len; i += 3) {
                  String s = new String(buffer, i, 3, "UTF-8");
                  System.out.printf(s);
              }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 在使用inputStream读取文件在缓冲区之后,如何解决字符编码格式不同的问题
    • 按照utf-8的编码格式,将3个字节合成一个字符进行读取
    • 使用Scanner,Scanner内部会自动进行编码格式的处理
// 处理字节转换成字符的编码格式问题
public static void main(String[] args) {
    // 按照utf-8的规则,将3个字节合成一个字节进行处理
    try (InputStream inputStream = new FileInputStream("./test.txt")) {
        byte[] buffer = new byte[1024];
        while (true) {
            int len = inputStream.read(buffer);
            if (len == -1) break;
            // 使用utf-8的标准,将每三个字节拼接成一个字符打印出来
            for (int i = 0; i < len; i += 3) {
                String s = new String(buffer, i, 3, "UTF-8");
                System.out.print(s);
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 使用Scanner进行文件内容的编码格式处理
    try (InputStream inputStream = new FileInputStream("./test.txt")) {
        // 将inputStream从文件中读取到的数据交给Scanner,让Scanner处理字符集的问题
        // Scanner使用完inputStream应该是要关闭的,但是由于外面包了一层try(),所以inputstream可以自动关闭
        // 如果Scanner接收的inputStream是System.in标准输入的话,一般不关闭
        try(Scanner scanner = new Scanner(inputStream)) {
            while (scanner.hasNext()) {
                System.out.print(scanner.next());
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 使用文件输出流FileOutputStream向文件中写入内容
// 使用OutputStream向文件写入内容
public static void main(String[] args) {
    // 创建一个OutputStream对象就会覆盖式写入内容到文件当中
    // 但是使用OutputStream对象中的方法(例如:write())写入都是追加式写入
    try (OutputStream outputStream = new FileOutputStream("./test.txt")) {
        // 写入一个字节
        outputStream.write('a');
        // 写入多个字节
        byte[] buffer = new byte[] {
                (byte)'a', (byte)'b', (byte)'c'
        };
        outputStream.write(buffer);
        // 将字符串转换成byte()格式
        String s = "hello world";
        outputStream.write(s.getBytes(
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 使用PrintWriter类托管FileOutputStream对象进行文件的写入
public static void main(String[] args) {
    // 使用PrintWriter类接收OutputStream对象打开的文件进行写入更方便
    // 使用PrintWriter对象中的方法可以像输出内容到显示屏一样,输出到文件中
    try (OutputStream outputStream = new FileOutputStream("./test.txt")) {
        try(PrintWriter printWriter = new PrintWriter(outputStream)) {
            printWriter.println("hello world");
        }
    }catch (IOException e) {
        e.printStackTrace();
    }
}

案例

  1. 在指定目录下寻找包含指定字符的所有文件,询问用户是否要判断
  • 考点:
    • 递归找到目录下的文件
    • 删除文件
// 指定一个目录,并输入需要查找文件的字符,扫描整个目录去寻找并询问用户有指定字符的文件是否要删除
public static void main(String[] args) throws IOException {
    // 获得需要扫描的目录
    System.out.print("请输入一个根目录(绝对路径): ");
    Scanner scanner = new Scanner(System.in);
    String root;
    while (true) {
        root = scanner.next();
        File rootDir = new File(root);
        if (!rootDir.isDirectory()) {
            System.out.println("输入的路径有误,请重新输入");
            continue;
        }
        break;
    }
    // 获得需要查找的文件包含的字母
    System.out.print("请输入文件包含的字符:");
    String token = scanner.next();
    // 扫描整个目录中的文件,将包含指定字符的文件放入res中
    List<String> res = new ArrayList<>();
    scanWholeDir(root, token, res);
    // 询问用户是否要删除找到的文件
    for (String file : res) {
        System.out.print(file + " 是否要删除 (Y/N): ");
        String input = scanner.next();
        if (input.equals("Y")) {
            File delFile = new File(file);
            delFile.delete();
        }
    }
}
private static void scanWholeDir(String root, String token, List<String> res) throws IOException {
    File file = new File(root);
    if (file.isFile()) {
        // 获得文件的决定路径
        String name = file.getCanonicalPath();
        // 判断文件的名字中是否包含指定字符
        if (name.contains(token)) {
            res.add(name);
        }
    } else {
        String[] files = file.list();
        for (String f : files) {
            scanWholeDir(root + "/" + f, token, res);
        }
    }
}
  1. 文件的复制
  • 考点:
    • 使用FileOutputStream进行文件内容的写入
// 进行文件的复制
public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    // 获得源文件地址
    System.out.print("请输入需要复制的文件的地址(绝对路径):");
    String srcPath = scanner.next();
    File srcFile = new File(srcPath);
    if (!srcFile.isFile()) {
        System.out.println("输入地址有误, 程序退出");
        return ;
    }
    // 获得目标文件地址
    System.out.print("请输入要将文件复制到的路径(绝对路径):");
    String destPath = scanner.next();
    File destFile = new File(destPath);
    if (destFile.exists()) {
        System.out.println("当前文件已存在,不能将文件复制到该文件中。程序退出");
        return ;
    }
    // 进行文件内容的拷贝
    try (InputStream inputStream = new FileInputStream(srcFile);
         OutputStream outputStream = new FileOutputStream(destFile)
            ) {
        byte[] buffer = new byte[1024];
        while (true) {
            int len = inputStream.read(buffer);
            if (len == -1) break;
            outputStream.write(buffer, 0, len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  1. 在指定目录下找出文件名或者文件内容包含指定字符的文件
  • 考点:
    • 递归查询文件名和文件内容
// 在指定目录中找出文件名包含或者文件内容包含关键字的文件
public static void main(String[] args) throws IOException {
    Scanner scanner = new Scanner(System.in);
    // 1. 获得需要搜索的根目录
    System.out.print("请输入根目录(绝对路径): ");
    String rootDir = scanner.next();
    File rootFile = new File(rootDir);
    if (!rootFile.isDirectory()) {
        System.out.println("路径错误,程序退出");
        return ;
    }
    // 2. 获得搜索的关键字
    System.out.print("请输入搜索关键字:");
    String query = scanner.next();
    // 3. 进行扫描
    List<File> res = new ArrayList<>();
    scanDirWithQuery(rootFile, query, res);
    // 4. 打印结果
    for (File file : res) {
        System.out.println(file.getCanonicalPath());
    }
}
private static void scanDirWithQuery(File rootFile, String query, List<File> res) {
    if (rootFile.isDirectory()) {
        File[] files = rootFile.listFiles();
        for (File f : files) {
            scanDirWithQuery(f, query, res);
        }
    } else {
        if (rootFile.getName().contains(query) ||
                contentContainQuery(rootFile, query)) {
            res.add(rootFile);
        }
    }
}
private static boolean contentContainQuery(File rootFile, String query) {
	// 将文件中的内容拼接成一个字符串,然后在这个字符串中查询指定的字符串是否存在
    StringBuffer stringBuffer = new StringBuffer();
    try (InputStream inputStream = new FileInputStream(rootFile)) {
        try (Scanner scanner = new Scanner(inputStream)) {
            while (scanner.hasNextLine()) {
                stringBuffer.append(scanner.nextLine() + "\n");
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return  stringBuffer.indexOf(query) != -1;
}

你可能感兴趣的:(Java,java,开发语言)