【文件操作——IO】

一、文件分类

在计算机中,文件是一个广义的概念,不只是包含普通文件,还可以包含目录(把目录称为目录文件)日常所说的文件夹。

操作系统中,还会使用文件来描述一些其他的硬件设备或者软件资源~~

站在程序猿的角度,主要把文件分成两类:

①.文本文件---》里面存储的是字符----》文本文件本质上也是村字节的.但是文本文件中,相邻的字节在一起正好能构成一个个字符~~

②.二进制文件----》存储的是字节

判定一个文件是文本还是二进制,一种简单的方法:用记事本打开~如果打开之后是乱码,就是二进制,不是乱码就是文本~

像日常中使用的 .txt、.c、.java都属于文本文件,.doc、.ppt、.exe、.zip、.class等等都属于二进制文件~~word、excel office 系列的文件一般都是二进制的~~

计算机里,保存管理文件是通过操作系统中的“文件系统”这样的模块来负责的~~

文件系统中,一般是通过“树形”结构来组织磁盘上的目录和文件的~~

在操作系统中,通过“路径”这样的概念来描述一个具体文件/目录的位置,路径有两种描述风格:

1.绝对路径:以盘符开头的.E:\JavaWork\JDBC\src

2.相对路径:以.或者..开头的,其中.表示当前路径,..表示当前路径的父目录(上级路径)

谈到相对路径,必须要先有一个基准目录~~相对路径就是从基准目录出发,按照一个啥样的路径找到对应的文件~~

二、Java操作文件

1.文件系统相关的操作

指的是通过“文件资源管理器”能够完成的一些功能~~

 在JAVA中提供了一个File类,通过这个类来完成上述操作.首先这个File类就描述了一个文件/目录,基于这个对象就可以实现上面的功能~~

相对路径,明确“基准路径”:

1、如果通过cmd的方式,此时执行命令所在的目录,就是基准路径~~

2、如果是通过IDEA的方式来运行程序,此时基准路径就是当前java项目所在的路径~~

 在IDEA中直接运行,基准路径就是上述目录~

3、把一个java代码打包成war包,放到tomcat上运行。这种情况下基准路径就是tomcat的bin目录~~

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\JavaWork\\test.txt");
        System.out.println(file.exists());//文件是否存在
        System.out.println(file.getParent());//获取到文件的父目录
        System.out.println(file.getName());//获取文件名
        System.out.println(file.getAbsoluteFile());//获取到绝对路径
        System.out.println(file.getCanonicalFile());//获取到绝对路径
        System.out.println(file.getPath());//获取到文件路径(构建File的时候指定的路径)
        System.out.println("===================");
        File file1 = new File("..\\test.txt");
        System.out.println(file1.exists());//文件是否存在
        System.out.println(file1.getParent());//获取到文件的父目录
        System.out.println(file1.getName());//获取文件名
        System.out.println(file1.getAbsoluteFile());//获取到绝对路径
        System.out.println(file1.getCanonicalFile());//获取到绝对路径,得到的是化简过得绝对路径
        System.out.println(file1.getPath());//获取到文件路径(构建File的时候指定的路径)
    }
}

 

 判断文件是否存在,如若不存在,则创建文件,并查看之后是否存在:

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test1.txt");
        System.out.println(file.exists());
        System.out.println("创建文件~");
        file.createNewFile();
        System.out.println("创建文件结束");
        System.out.println(file.exists());
    }
}

 

 删除文件的操作:

public class Demo3 {
    public static void main(String[] args) {
        File file = new File("./test1.txt");
        file.delete();
    }
}

 创建目录:

public class Demo5 {
    public static void main(String[] args) {
        File file = new File("./aaa");
        file.mkdir();//创建目录
        System.out.println(file.isDirectory());
        File file1 = new File("./first/second/third");
        file1.mkdirs();//创建多级目录
        System.out.println(file1.isDirectory());
    }
}

 罗列某个目录下所包含的文件:

public class Demo4 {
    public static void main(String[] args) {
        File file = new File("./first");
        System.out.println(Arrays.toString(file.list()));
    }
}

 重命名:

public class Demo6 {
    public static void main(String[] args) {
        File file = new File("./first");
        File file1 = new File("第一");
        file.renameTo(file1);
    }
}

2.文件内容相关的操作

核心操作:打开文件、读文件、写文件、关闭文件

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

(一).字节流对象,针对二进制文件,是以字节为单位进行读写的

读:InputStream

public class Demo7 {
    public static void main(String[] args) throws IOException {
        //构造方法中需要指定打开文件的路径
        //可以是绝对路径,也可以是相对路径,还可以是File对象
        //1.创建对象,打开文件
        InputStream inputStream = new FileInputStream("./test.txt");
        //2.尝试一个字节一个字节的读,把整个文件都读完
        while (true){
            int b = inputStream.read();
            if(b == -1){//读到了文件末尾
                break;
            }
            System.out.println(b);
        }
        //3.读完之后关闭文件
        inputStream.close();
    }
}

 

 

 此时读出来的这些数字,就是每个字符的ascii码值,由于这些英文字符本身就是一个字节的,这里按照字节读取的效果就是如此~~

 如果上述代码执行到一半捕捉到了异常,那如何才能关闭InputStream呢?

public class Demo7 {
    public static void main(String[] args) {
        //构造方法中需要指定打开文件的路径
        //可以是绝对路径,也可以是相对路径,还可以是File对象
        //1.创建对象,打开文件
        try(InputStream inputStream = new FileInputStream("./test.txt");){
            //2.尝试一个字节一个字节的读,把整个文件都读完
            while (true){
                int b = inputStream.read();
                if(b == -1){
                    break;
                }
                System.out.println(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/*
在这个代码中,没有显式的调用close,
但是try会帮我们自动调用~~当代码执行完这里的try语句块之后,就会自动的调用close
 */

 得符合一定的条件,才能放到try()中,实现Closeable这个interface,恰好所有的流对象,都实现了Closeable~~所以就可以直接释放了~~~

public class Demo8 {
    public static void main(String[] args) {
        try(InputStream inputStream = new FileInputStream("./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) {
            e.printStackTrace();
        }
    }
}

写:OutputStream

//使用字节流写文件
public class Demo9 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("./test.txt")) {
            //一次写一个字符
//            outputStream.write(97);
//            outputStream.write(98);
//            outputStream.write(99);
            //一次写多个字符
            byte[] buffer = new byte[]{97,98,99};
            outputStream.write(buffer);
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 每次按照写方式打开文件,都会清空原有文件内容,清空旧的内容,再从起始位置往后写的~~

 还有一种追加写的流对象,打开之后不清空,从文件末尾继续往后写~~

需要在构造时,参数设为true~~~

try(OutputStream outputStream = new FileOutputStream("./test.txt",true)

(二).字符流对象,针对文本文件,是以字符为单位进行读写的

读:Reader

//按照字符来读写
public class Demo10 {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("./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) {
            e.printStackTrace();
        }
    }
}

写:writer

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

 三.案例

案例一:

//文件操作案例1:扫描指定目录,再输入一个要删除的文件名,
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 DeleteName = scanner.next();
        File rootDir = new File(rootDirPath);
        if(!rootDir.isDirectory()){
            System.out.println("输入的扫描路径有误~~");
            return;
        }
        //2.遍历目录,把指定目录中的所有文件和子目录都遍历一遍,从而找到要删除的文件
        //通过这个方法,来实现递归遍历并删除的操作
        scanDir(rootDir,DeleteName);
    }

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

    private static void deleteFile(File f) {
        try {
            System.out.println(f.getCanonicalFile() + "确认要删除嘛?Y/N");
            Scanner scanner = new Scanner(System.in);
            String str = scanner.next();
            if(str.equals("Y") || str.equals("y")){
                f.delete();
            }else if(str.equals("N") || str.equals("n")){
                System.out.println("取消删除~");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

案例二:

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

//案例二:进行普通文件的复制~~
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都写进去,毕竟buffer可能是只有一部分才是有效数据
                    outputStream.write(buffer,0,len);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

案例三:

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

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 file = new File(rootDirPath);
        if(!file.isDirectory()){
            System.out.println("输入的路径非法~");
            return;
        }
        //2.递归的进行遍历
        scanDir(file,word);
    }

    private static void scanDir(File file, String word) throws IOException {
        //1.先列出file中都有哪些内容
        File[] files = file.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 sb = 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中
                sb.append(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //indexOf返回的是子串的下标,如果word在StringBuilder中不存在,则返回下标为-1
        return sb.indexOf(word) != -1;
    }
}

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值