操作系统 --- 文件操作和IO

x33g5p2x  于2022-03-31 转载在 其他  
字(12.9k)|赞(0)|评价(0)|浏览(560)

1. 文件路径

绝对路径

绝对路径 (absolute path) : 以一个盘符开头的路径,就是绝对路径
例如这里的 D:\java\IntelliJ IDEA Community Edition 2021.2.2\bin\idea64.exe 就是绝对路径

相对路径

相对路径 (relative path) 一般是以.或者..开头的路径.一般会有一个基准,去找对应的路径.
.就是当前目录 ..当前目录的上一目录
例如

  • D:\java\IntelliJ IDEA Community Edition 2021.2.2\bin作为基准 相对路径可以写成.\idea64.exe
  • D:\java\IntelliJ IDEA Community Edition 2021.2.2作为基准 相对路径可写成.\bin\idea64.exe
  • D:\java\IntelliJ IDEA Community Edition 2021.2.2\bin\idea64.exe作为基准 相对路径可用写成..\idea64.exe

2. Java中操作文件

Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。

2.1 File 的常用属性,方法和构造方法

属性

修饰符及类型属性说明
static StringpathSeparator依赖于系统的路径分隔符,String 类型的表示
static charpathSeparator依赖于系统的路径分隔符,char 类型的表示

构造方法

签名说明
File(File parent, String child)根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname)根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, String child)根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示

方法

方法签名说明
String getParent()返回 File 对象的父目录文件路径
String getName()返回 FIle 对象的纯文件名称
String getPath()返回 File 对象的文件路径
String getAbsolutePath()返回 File 对象的绝对路径
String getCanonicalPath()返回 File 对象的修饰过的绝对路径
boolean exists()判断 File 对象描述的文件是否真实存在
boolean isDirectory()判断 File 对象代表的文件是否是一个目录
boolean isFile()判断 File 对象代表的文件是否是一个普通文件
boolean createNewFile()根据 File 对象,自动创建一个空文件。成功创建后返回 true
boolean delete()根据 File 对象,删除该文件。成功删除后返回 true
void deleteOnExit()根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行
String[] list()返回 File 对象代表的目录下的所有文件名
File[] listFiles()返回 File 对象代表的目录下的所有文件,以 File 对象表示
boolean mkdir()创建 File 对象代表的目录
boolean mkdirs()创建 File 对象代表的目录,如果必要,会创建中间目录
boolean renameTo(File dest)进行文件改名,也可以视为我们平时的剪切、粘贴操作
boolean canRead()判断用户是否对文件有可读权限
boolean canWrite()判断用户是否对文件有可写权限

注意: 这里的有File对象,不代表这个文件一定真实存在

使用示例1: get相关方法的使用

import java.io.File;
import java.io.IOException;

public class FileDemo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");//这里的test.txt不一定存在
        System.out.println(file.getParent());
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getCanonicalPath());
    }
}

运行结果截图:

使用示例2: 普通文件的创建和删除

import java.io.File;
import java.io.IOException;

public class FileDemo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");
        System.out.println("创建前:");
        System.out.println("文件是否真实存在: "+file.exists());
        System.out.println("文件是否是一个目录: "+file.isDirectory());
        System.out.println("文件是否是一个普通文件: "+file.isFile());
        System.out.println("创建后:");
        System.out.println("文件创建是否成功: "+file.createNewFile());
        System.out.println("文件是否真实存在: "+file.exists());
        System.out.println("文件是否是一个目录: "+file.isDirectory());
        System.out.println("文件是否是一个普通文件: "+file.isFile());
        System.out.println("再次创建:");
        System.out.println("文件创建是否成功: "+file.createNewFile());
    }
}

运行结果截图:

使用示例3: deleteOnExit 的使用

import java.io.File;
import java.io.IOException;

public class FileDemo3 {
    public static void main(String[] args) throws IOException, InterruptedException {
        File file = new File("./test.txt");
        System.out.println(file.exists());
        System.out.println(file.createNewFile());
        System.out.println(file.exists());

        Thread.sleep(3000);
        file.deleteOnExit();
        System.out.println(file.exists());
    }
}

代码截图:
发现运行过程中,三秒之后,输出文件存在之后,文件被删除

使用示例4: 单级目录的创建

import java.io.File;

public class FileDemo4 {
    public static void main(String[] args) {
        File file = new File("test");
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.mkdir());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
    }
}

运行截图:

使用示例5: 多级目录的创建

import java.io.File;

public class FileDemo5 {
    public static void main(String[] args) {
        File file = new File("aaa/bbb/ccc");
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.mkdirs());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
    }
}

运行截图:

使用示例6: 文件的重命名

import java.io.File;
import java.io.IOException;

public class FileDemo6 {
    public static void main(String[] args) throws IOException {
        File file1 = new File("./test.txt");
        File file2 = new File("./test2.txt");
        System.out.println(file1.exists());
        System.out.println(file1.createNewFile());
        System.out.println(file1.exists());
        System.out.println(file1.renameTo(file2));
    }
}

运行截图:

使用示例7: 文件的移动

import java.io.File;

public class FileDemo7 {
    public static void main(String[] args) {
        File file1 = new File("./test2.txt");
        File file2 = new File("./aaa/test2.txt");
        file1.renameTo(file2);
    }
}

运行截图:

使用示例8: 打印当前目录下所有的文件名

import java.io.File;
import java.util.Arrays;

public class FileDemo8 {
    public static void main(String[] args) {
        File file = new File(".");

        String[] files = file.list();
        System.out.println(Arrays.toString(files));
    }
}

运行截图:

2.2 面试题(遍历一个目录下所有的文件,包含子目录的文件)

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class FileDemo9 {
    // 这里的result 用来记录每一个目录里面的路径
    public static List<String> result = new ArrayList<>();

    public static void getAllFiles(String basePath){
        File file = new File(basePath);
        if(file.isFile()){
            //如果是一个文件就之间add
            result.add(basePath);
            return ;
        }else if (file.isDirectory()){
            //这里是一个目录 就需要递归
            String[] files = file.list();
            for (String f : files){
                getAllFiles(basePath+"/"+f);
            }
        }else{
            //非普通文件,暂不考虑
        }
    }

    public static void main(String[] args) {
        getAllFiles(".");
        for (String s : result){
            System.out.println(s);
        }
    }
}

运行结果:

3. 文件内容的读写 – 数据流

3.1 InputStream — — 读

方法

方法说明
int read()读取一个字节的数据,返回 -1 代表已经完全读完了
int read(byte[] b)最多读取 b.length 字节的数据到 b 中,返回实际读到的数量;-1 代表以及读完了
int read(byte[] b,int off, int len)最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表以及读完了
void close()关闭字节流

注: InputStream是一个抽象类.可用使用FileInputStream来实现.

FileInputStream 的构造方法

构造方法说明
FileInputStream(File file)利用 File 构造文件输入流
FileInputStream(String name)利用文件路径构造文件输入流

使用示例1: 一次读写一个字符

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

public class FileDemo10 {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream = new FileInputStream("test.txt")){
            while (true){
                int b = inputStream.read();
                if(b == -1){
                    break;
                }
                System.out.printf("%c",b);
            }
        }
    }
}

运行结果:

使用示例2: 一次读多个字符

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

public class FileDemo11 {
    public static void main(String[] args) throws IOException {
        try (InputStream inputStream = new FileInputStream("test.txt")){
            byte[] bytes = new byte[1024];
            while(true) {
                int len = inputStream.read(bytes);
                if(len == -1){
                    break;
                }
                for (int i = 0; i < len; i++) {
                    System.out.printf("%c",bytes[i]);
                }
            }
        }
    }
}

注: 示例2比示例1更好,因为IO次数少,性能也就更好

使用示例3: 当文件中的内容是中文时

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

public class FileDemo12 {
    public static void main(String[] args) throws IOException {
        try (InputStream inputStream = new FileInputStream("test.txt")){
            byte[] bytes = new byte[1024];
            while (true){
                int len = inputStream.read(bytes);
                if(len == -1){
                    break;
                }
                // 中文是占3个字节的
                for (int i = 0; i < len; i+=3) {
                    String s = new String(bytes,i,3,"UTF-8");
                    System.out.printf("%s",s);
                }
            }
        }
    }
}

注: 这里只是适用于全是中文的情况,这个只是了解,并不适用

使用示例4: 使用Scanner进行字符读取

构造方法说明
Scanner(InputStream is, String charset)使用 charset 字符集进行 is 的扫描读取
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class FileDemo13 {
    public static void main(String[] args) throws IOException {
        try (InputStream inputStream = new FileInputStream("test.txt")){
            Scanner scanner = new Scanner(inputStream,"UTF-8");
            while (scanner.hasNext()){
                String s = scanner.nextLine();
                System.out.print(s);
            }
        }
    }
}

3.2 OutputStream — — 写

方法

方法说明
void write(int b)写入要给字节的数据
void write(byte[] b)将 b 这个字符数组中的数据全部写入 os 中
int write(byte[] b, int off,int len)将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个
void close()关闭字节流
void flush()重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。

注: OutputStream 也是一个抽象类,可以使用FileOutputStream来实现

使用示例1: 一次写入一个字符

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class FileDemo14 {
    public static void main(String[] args) throws IOException {
        try (OutputStream outputStream = new FileOutputStream("test.txt")){
            outputStream.write('h');
            outputStream.write('e');
            outputStream.write('l');
            outputStream.write('l');
            outputStream.write('o');
            outputStream.flush();
        }
    }
}

使用示例2: 一次写入多个字符

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class FileDemo15 {
    public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("test.txt")){
            byte[] bytes = new byte[]{
                    (byte) 'h',(byte) 'e',(byte) 'y'
            };
            outputStream.write(bytes);
            outputStream.flush();
        }
    }
}

使用示例3: 使String来辅助写入字符

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FileDemo15 {
    public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("test.txt")){
            String str = "hello world";
            outputStream.write(str.getBytes());
            outputStream.flush();
        }
    }
}

使用示例4: 利用 PrintWriter 类来辅助写入字符

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;

public class FileDemo16 {
    public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("test.txt")){
            try(PrintWriter writer = new PrintWriter(outputStream)){
                writer.println("hello 你好");
            }
        }
    }
}

4. 实现一些案例

案例1:

扫描一个指定的目录,并找到名称中包含指定字符的所有普通文件,并且根据用户的选择来判断是否要删除文件.

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

public class Delete {
    public static void main(String[] args) throws IOException {
        // 1. 用户输入路径
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入需要扫描的根路径: ");
        String rootDirPath = sc.nextLine();

        // 2. 如果输入的根目录不存在,之间返回
        File file = new File(rootDirPath);
        if(!file.isDirectory()){
            System.out.println("您输入的目录错误!退出程序!");
            return;
        }
        // 3. 用户输入需要查找的文件名中的内容
        System.out.print("请输入要查找的文件名中含有的字符: ");
        String name = sc.nextLine();

        // 4. 递归遍历目录,并把满足条件的路径存入 result 中
        List<File> result = new ArrayList<>();
        scanDir(file,name,result);

        // 5. 打印result中的内容 由用户决定是否删除
        if(result.size() == 0) {
            System.out.println("没有要找的文件!");
            return;
        }
        for(File f : result){
            System.out.println(f.getCanonicalFile());
            System.out.println("请问是否删除这个文件(Y/N)");
            String decision = sc.nextLine();
            if(decision.equals("Y")){
                f.delete();
                System.out.println("删除成功!");
                return;
            }
        }
    }

    private static void scanDir(File file, String name, List<File> result) {
        File[] files = file.listFiles();
        // 判断一下 files 是不是空或者files是不是没有东西
        if (files == null || files.length == 0) {
            //空目录
            return;
        }

        for(File f:files){
            if(f.isDirectory()){
                //是目录就进行查找
                scanDir(f,name,result);
            }else{
                // 不是目录就判断名字是否带有需要查找的关键字 使用contains方法
                if(f.getName().contains(name)){
                    result.add(f.getAbsoluteFile());
                }
            }
        }
    }

}

案例2:

进行普通文件的复制

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

public class Copy {
    public static void main(String[] args) throws IOException {
        // 1. 让用户输入要复制的文件路径
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入要复制文件的路径: ");
        String srcPath = sc.nextLine();
        File srcFile = new File(srcPath);
        // 2. 判断输入的是否是文件,不是就返回
        if(!srcFile.isFile()){
            System.out.println("输入的文件路径错误!程序结束!");
            return;
        }
        // 3. 是文件 就输入要复制到的路径
        System.out.print("请输入要复制到的目标路径: ");
        String destPath = sc.nextLine();
        File destFile = new File(destPath);
        // 4. 判断是否存在复制后的文件,如果有就返回复制失败
        if(destFile.exists()){
            System.out.println("该目录已有该文件,复制失败!");
            return;
        }
        // 5. 判断父级目录存不存在 不存在就创建目录
        if(!destFile.getParentFile().exists()){
            destFile.getParentFile().mkdirs();
        }
        // 6. 复制文件
        try (InputStream inputStream = new FileInputStream(srcFile); OutputStream outputStream = new FileOutputStream(destFile)) {
            while(true) {
                byte[] bytes = new byte[1024];
                int len = inputStream.read(bytes);
                if(len == -1){
                    break;
                }
                outputStream.write(bytes,0,len);
            }
            outputStream.flush();
        }
        System.out.println("复制完成!!!");
    }
}

案例3:

扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Search {
    public static void main(String[] args) throws IOException {
        // 1. 用户输入要扫描的目录路径
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入要查找的文件的目录的路径: ");
        String searchPath = sc.nextLine();
        File file = new File(searchPath);
        // 2. 判断是否存在目录
        if(!file.isDirectory()) {
            System.out.println("输入的目录路径错误!程序结束!");
            return;
        }
        // 3. 用户输入要查找的内容
        System.out.print("请输入你要查找的内容: ");
        String str = sc.nextLine();
        List<File> result = new ArrayList<>();
        // 4. 用递归的方式遍历 符合的存入result
        scanResult(file,str,result);

        // 5. 遍历结果
        System.out.println("找到了"+result.size()+"个符合条件的内容");
        for(File file1 : result){
            System.out.println(file1.getCanonicalFile());
        }
    }
    public static void scanResult (File file,String str,List<File> result) throws IOException {
        // files里都是目录
        File[] files = file.listFiles();
        // files为空或者长度为0就是没有内容 直接返回
        if(files == null || files.length == 0){
            return;
        }
        // 遍历
        for(File f : files){
            // 是目录就递归
            if(f.isDirectory()){
                scanResult(f,str,result);
            }else{
                // 不是目录就判断是否准则符合要求的内容
                if(isContains(f,str)){
                    result.add(f);
                }
            }
        }
    }
    public static boolean isContains(File f,String s) throws IOException{
        StringBuilder sb = new StringBuilder();
        try(InputStream inputStream = new FileInputStream(f)){
            try(Scanner sc = new Scanner(inputStream,"UTF-8")){
                // 读取数据
                // 每一行的读
                // 并添加到sb中
                while (sc.hasNextLine()){
                    String str = sc.nextLine();
                    sb.append(str+"/n");
                }
            }
        }
        // 如果和-1相等就是没有要找的内容
        return sb.indexOf(s) == -1;
    }
}

相关文章