文件操作与IO

目录

一.什么是文件 

二.文件的分类

三.Java中的文件操作 

 四.文件操作案例


一.什么是文件 

平时我们锁说到的文件一般指的都是存储在硬盘上的普通文件,形如txt,png,jpg,等等这些都是普通文件,都存储在硬盘上.而在计算机中,文件可能是一个广义的概念,就不再是只包含普通文件,还可以包含目录(也就是"文件夹"一般把目录称为目录文件),而在这里我们主要针对普通文件来展开说!

这个就是存储普通文件的机械硬盘,机械硬盘的基本构造:1.盘片,存储数据的介质2.磁头

机械硬盘的运作:机械硬盘一旦上电,里面的盘片就会高速运转,磁头就会在盘片上找到对应的数据 

另外还有固态硬盘(SSD),固态硬盘的结构和机械硬盘的是截然不同的,而固态硬盘的读写速度要比机械硬盘高很多,但固态硬盘会更贵一些

二.文件的分类

站在程序员的角度上,我们一般把文件分成两类:文本文件(存储字符)和二进制文件(存储字节)

这两种文件在编程上也会存在一定差异

简单的判断文件方法:用记事本打开,如果是乱码就是二进制文件,不是乱码就是文本文件

像这样的乱码就是二进制文件 

关于目录结构

计算机中,保存管理文件,是通过操作系统中的"文件系统"这样的模块来负责的,文件系统中一般是通过"树形"(N叉树)结构在组织磁盘上的目录和文件的

 整体的文件系统就是这种树形结构来存储的,如果是普通文件就是树的叶子结点,如果是目录文件,目录中就可以包含子树,这个目录就是非叶子结点,这个树每个节点的子树都可以有N个,这就是一个N叉树了

而在操作系统中就通过"路径"这样的概念,来描述一个一个具体文件/目录的位置~

路径这里有两种描述风格:

1.绝对路径

绝对路径指的就是一个具体的路径,以盘符开头的,例如E:\NEW\test.txt这样的路径,可以直接找到文件的路径

2.相对路径

以.或者..开头的,其中.表示当前路径..表示当前路径的父目录(上级路径),相对路径就必须要有一个基准目录,相对路径就是从基准目录出发,按照基准路径出发来找到相对应的文件,

例如以C:\Program Files\Java\jdk1.8.0_192\bin为基准路径,找到javac.exe,./javac.exe其中.就代表当前的基准路径,而要找到src.zip就可以这样写../src.zip,..就相当于回到了基准的上一层路径(C:\Program Files\Java\jdk1.8.0_192),再来找目标路径

即使定位到同一个路径,但基准路径不同的话,相对路径也是不同的!

三.Java中的文件操作 

Java中的文件操作主要包含两类操作:

1.文件系统相关的操作

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

①列出目录中有哪些文件②创建文件③创建目录④删除文件⑤重命名文件...

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

import java.io.File;
import java.io.IOException;
public class Demo1 {
    public static void main(String[] args) throws IOException {
        File f = new File("E:/NEW/test.txt");//构造函数传入了一个路径,这个路径可以使相对路径也可以是绝对路径,这里是绝对路径


        System.out.println(f.getParent());//获得当前的父目录
        System.out.println(f.getName());//获取文件名
        System.out.println(f.getPath());//获取文件的路径(构造file的路径)
        System.out.println(f.getAbsolutePath());//获取绝对路径
        System.out.println(f.getCanonicalPath());//获取绝对路径   会有异常,表示输入输出的异常
        System.out.println("============");

        File f1 = new File("./test.txt");

        System.out.println(f1.getParent());//获得当前的父目录
        System.out.println(f1.getName());//获取文件名
        System.out.println(f1.getPath());//获取文件的路径(构造file的路径)
        System.out.println(f1.getAbsolutePath());//获取绝对路径  拼接基准路径和相对路径,但是这里的点表示的仍然是当前路径,因此我们可以完全不要这个路径
        System.out.println(f1.getCanonicalPath());//获取绝对路径    化简过的绝对路径
    }
}

 判断文件是否存在

import java.io.File;
public class Demo2 {
    public static void main(String[] args) {
        File f = new File("E:/NEW/test.txt");
        System.out.println(f.exists());//是否存在
        System.out.println(f.isDirectory());//是否是目录
        System.out.println(f.isFile());//是否是文件

    }
}

 创建文件

import java.io.File;
import java.io.IOException;
public class Demo3 {
    public static void main(String[] args) throws IOException {
        File f = new File("./text.txt");
        System.out.println("文件是否存在 " + f.exists());
        System.out.println("创建文件");
        f.createNewFile();
        System.out.println("创建文件结束");
        System.out.println("文件是否存在 " + f.exists());
    }
}

 删除文件

import java.io.File;
public class Demo4 {
    public static void main(String[] args) {
        File f = new File("./text.txt");
        f.delete();//删除文件(立即删除)
        System.out.println("完成删除");

    }
}

 创建目录

import java.io.File;
public class Demo5 {
    public static void main(String[] args) {
        File f = new File("./aaa");
        f.mkdir();//创建目录

    }
}

import java.io.File;
public class Demo5 {
    public static void main(String[] args) {
        File f = new File("./aaa/bbb/ccc/ddd");
        f.mkdirs();//创建多级目录
    }
}

 查看目录下的所有内容

import java.io.File;
import java.util.Arrays;
public class Demo6 {
    public static void main(String[] args) {
        File f = new File("./");
        System.out.println(Arrays.toString(f.list()));//查看此目录下的内容(列出目录内容)
        System.out.println(Arrays.toString(f.listFiles()));//按照file对象的方法打印
    }
}

 改名字

import java.io.File;
public class Demo7 {
    public static void main(String[] args) {
        File f = new File("./aaa");
        File f1 = new File("./zzz");
        f.renameTo(f1);//改名字,将f的名字改成f1的内容
    }
}

上面这些操作都非常简单,也是我们常常使用的,因此还是需要掌握的 

2.文件内容相关的操作

①打开文件

②读文件

③写文件

④关闭文件

针对文件内容的读写,Java标准库提供了一组类

按照文件的内容,分成了两个系列:

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

读:InputStream

写:OutputStream

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

读:Reader

写:Writer

上面四组类都是抽象类(这些抽象类既可以针对普通文件的读写,也可以针对特殊文件(网卡,socket)来进行读写),都是不能具体实现的,要实现的话往往是这些类的子类来实现:FileInputStream,FileOutputStream,FileReader,FileWriter,这些都是特指针对普通文件进行读写的

InputStream



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

public class Demo8 {
    public static void main(String[] args) {
        InputStream inputStream = null;
        try {//创建对象,也是打开文件,有可能没有文件,因此需要抛异常
            inputStream = new FileInputStream("E:/NEW/test.txt");//需要指定路径,可以是相对路径也可以是绝对路径,也可以是File对象
            //尝试一个一个字节的读,把整个文件读完
            while(true){
                int x = inputStream.read();
                if(x == -1){
                    break;//表示读完了所有的字节
                }
                System.out.println(x);//打印
            }

        } catch (IOException e) {//这个包含了FileNotFoundException(子类),因此可以合并,IO操作失败的可能性是非常大的
            e.printStackTrace();
        }finally {
            //读完之后需要关闭文件,释放资源
            try {
                inputStream.close();//这个放在finally里面更好有需要把定义放到外面去
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

这个read()方法有三个版本的重载,无参数版本一次读一个,返回值为int,不是byte(-128~127,这个后面无法判断是否读完了所有字节),返回值的范围是-1~255,因此需要使用更大的类型来表示返回值,这里的-1就表示已经读完了所有字节,字节流结束了
 一个参数版,一次读若干个字节把读的结果仿造参数中指定的数组中去,返回的就是读到的字节数
三个参数版本,一次读若干个字节把读的结果仿造参数中指定的数组中去,返回的就是读到的字节数,不是从起始位置读起,而是从中间位置读起,最后一个表示能放多少个元素

我们可以看到这里写的还是挺麻烦的,其实Java里面提供了一个语法,可以在try里面自己关闭文件:



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

public class Demo9 {
    public static void main(String[] args) {
        //这里要放到try里面,得实现Closeable接口,才可以自动关闭,而所有的流对象都有这个接口
        try(InputStream inputStream = new FileInputStream("E:/NEW/test.txt");) {//这样就可以不用写close语句,try就会隐式的关闭文件,这样写就会简单很多
            while(true){
                /*int x = inputStream.read();//一次读一个
                if(x == -1){
                    break;//表示读完了所有的字节
                }*/
                byte[] b = new byte[1024];
                //这个会更常见一些比一次读一个更高效一些
                int x = inputStream.read(b);//一次读多个,这里x的含义表示方法的返回值,这种做法称为"输出型参数",表示数组有多少个元素,
                if(x == -1){
                    break;//表示读完了所有的字节
                }
                for(int i = 0;i < x;i ++){
                    //打印
                    System.out.println(b[i]);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

OutputStream

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

public class Demo10 {
    public static void main(String[] args) {
        try (OutputStream outputStream = new FileOutputStream("E:/NEW/test.txt")) {
            /*outputStream.write(97);
            outputStream.write(97);
            outputStream.write(97);
            outputStream.write(97);一次写一个
            outputStream.write(97);*/
            //也可以一次写多个
            byte[] b = new byte[]{97,97,97};
            outputStream.write(b);//一次写多个     这里的写操作每次按照写方式打开文件,都会清空原有的文件的内容,然后再从起始位置往后写
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Reader


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

public class Demo11 {
    public static void main(String[] args) {
        try(Reader reader = new FileReader("E:/NEW/test.txt")) {
            while (true){
                char[] c = new char[1024];
                int x = reader.read(c);//一次读多个
                if(x == -1){
                    break;
                }
                /*for (int i = 0; i < x; i++) {
                    System.out.println(c[i]);

                }*/
                String s = new String(c,0,x);//如果传入的是byte也可以指定字符编码
                System.out.println(s);//这样也可以读
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Writer

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Demo12 {
    public static void main(String[] args) {
        try(Writer writer = new FileWriter("E:/NEW/test.txt")){
            writer.write("xyz");//写操作
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 四.文件操作案例

 下面写几个文件操作的案例,再熟悉一下这些操作

1.实现查找文件并删除文件
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
//实现查找文件并删除文件
public class Demo13 {
    public static void main(String[] args) {
        //先输入要扫描的目录,以及要删除的文件名
        Scanner input = new Scanner(System.in);
        System.out.println("请输入要扫描的路径:");
        String rootDirPath = input.next();
        System.out.println("请输入要删除的文件名:");
        String toDeleteName = input.next();
        File rootDir = new File(rootDirPath);//构建文件对象
        if(!rootDir.isDirectory()){
            //不是一个目录
            System.out.println("你输入的路径有误");
            return;//可以抛一个异常
        }
        //遍历这个目录,寻找要删除的文件
        scanDir(rootDir,toDeleteName);
    }
    public static void scanDir(File rootDir,String toDeleteName){
        File[] files = rootDir.listFiles();
        if(files == null){
            //rootDir是空目录,返回
            return;
        }
        //不是空目录就遍历此目录里面的所有内容,如果是普通文件就看是不是要删除的文件,不是文件是目录的话,就再遍历这个目录
        for(File f : files){//列出rootDir里面有什么内容
            if(!f.isFile()){
                scanDir(f,toDeleteName);
            }
            if(f.isFile()){
                if(f.getName().contains(toDeleteName)){
                    //不要求名字完全一样,只要文件名中包含了关键字就可以删除
                    //进行删除操作
                    deleteFile(f);
                }
            }
        }
    }
    public static void deleteFile(File f){
        try {
            System.out.println(f.getCanonicalPath() + "确认要删除文件吗(Y/N)");
            Scanner input = new Scanner(System.in);
            String chose = input.next();
            if(chose.equals("Y") || chose.equals("y")){
                f.delete();//进行删除
                System.out.println("文件删除成功");
            }else{
                System.out.println("文件放弃删除");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

2.文件复制

import java.io.*;
import java.util.Scanner;
//文件复制,需要让用户支出两个文件路径,一个是原路径(被复制的文件),另一个是目标路径(复制后生成的文件)
public class Demo14 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入要拷贝的源路径:");
        String str = input.next();
        System.out.println("请输入要拷贝的目标路径:");
        String sub = input.next();
        File file = new File(str);
        if(!file.isFile()){//需要判断是不是正确的路径,目标路径不需要判断,因为没有的话,是会自己创建的
            System.out.println("不是一个正确的源路径");
            return;
        }
        //将源文件里面的内容读出来,然后再用写操作写到目标文件中去
        try(InputStream inputStream = new FileInputStream(str)) {
            try(OutputStream outputStream = new FileOutputStream(sub)) {
                byte[] b = new byte[1024];
                while(true){
                    int x = inputStream.read(b);
                    if(x == -1){
                        break;
                    }
                    outputStream.write(b,0,x);//需要指定长度,不能把所有的b都放进去
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.进行文件内容的查找

import java.io.*;
import java.util.Scanner;
//进行文件内容的查找,扫描指定目录,找到名称或内容中包含指定字符的所有普通文件(不包含目录)
public class Demo15 {
    public static void main(String[] args) throws IOException {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入要扫描的文件路径:");
        String rootDirPath = input.next();
        System.out.println("请输入要查询的关键字:");
        String word = input.next();
        File rootDir = new File(rootDirPath);
        if(!rootDir.isDirectory()){
            System.out.println("输入的路径非法!");
            return;
        }
        sDir(rootDir,word);
    }

    private static void sDir(File rootDir, String word) throws IOException {
        File[] files = rootDir.listFiles();
        if(files == null){
            return;
        }
        for (File f:files) {
            if(f.isDirectory()){
                sDir(f,word);
            }
            if(f.isFile()){
                //针对文件进行查找
                if(containsWord(f,word)){
                    System.out.println(f.getCanonicalPath());
                }
            }
        }
    }

    private static boolean containsWord(File f, String word) {
        StringBuilder stringBuilder = new StringBuilder();
        //把f中的内容都读出来,放到StringBuilder中,看是否包含关键字
        try(Reader reader = new FileReader(f)){
            char[] c = new char[1024];
            while(true){
                int x = reader.read(c);
                if(x == -1){
                    break;
                }
                stringBuilder.append(c,0,x);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //indexOf返回的是子串的下标,如果word存在,那么下标一定不是-1,
        return stringBuilder.indexOf(word) != -1;
    }
}

 

这里主要还是要多一下熟悉这些文件操作的类方法!!

猜你喜欢

转载自blog.csdn.net/qq_58266033/article/details/123968734
今日推荐