文件IO操作

一、文件的基础知识

1、文件可分为侠义和广义

侠义的文件

是指存储在硬盘上的数据,以文件为单位进行组织。常见的就是普通的文件(如文本文件,视频,图片,可执行文件等)

文件夹是一种特殊的文件,也叫做目录

广义的文件

操作系统要负责软硬件资源的管理,而操作系统往往会把这些都统一的抽象为“文件”来经行管理。

例如

网卡:就是把网卡这个设备抽象成一个文件,创建出一个特殊的文件,表示网卡。从网卡接受到的数据,就读进这个文件。往网卡里发送数据,就写入这个文件。

键盘:从键盘读取数据,也是把键盘抽象成一个文件(stdin),读设个文件就能读到用户输入的按键内容了。

本文讨论的文件是侠义的文件。

2、描述文件位置

描述文件的具体位置,分为绝对路径和相对路径。

1)绝对路径:从盘符(C盘,D盘.....)开始,目录之间用\(或者/)分隔。

如    D:\Program Files(x86)\Tencent\WeChat\WeChat.exe

2)相对路径:要先确定一个基准路径,以它为起点。

如绝对路径的栗子:

如果基准路径是D: 

        此时相对路径就是  .\Program Files(x86)\Tencent\WeChat\WeChat.exe

如果基准路径是D:\Program Files(x86)\Tencent\WeChat:

        此时相对路径就是.\WeChat.exe

二、File类

文件操作是属于操作系统层面的,操作系统会提供一些API。所以不同操作系统提供的API是不一样的。

而JAVA作为一个跨平台的语言,为了统一代码,在JVM中把不同系统的API进行封装。JAVA就可以使用JAVA中的库的代码来操作文件了。

Java 中通过 java.io.File 类对一个文件(包括目录)进行操作。

1、get基本信息

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

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File f = new File("./test.txt");

        System.out.println(f.getParent());
        System.out.println(f.getName());
        System.out.println(f.getPath());
        System.out.println(f.getAbsolutePath());
        System.out.println(f.getCanonicalPath());

    }

}

2、判断文件是否存在,不存在就创建。

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

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File f = new File("./test.txt");
        //判断文件名
        System.out.println(f.exists());
        //判断是否为目录
        System.out.println(f.isDirectory());
        //判断是否为文件
        System.out.println(f.isFile());
        //创建文件
        f.createNewFile();
        System.out.println("__________");
        //判断文件名
        System.out.println(f.exists());
        //判断是否为目录
        System.out.println(f.isDirectory());
        //判断是否为文件
        System.out.println(f.isFile());

    }
}

3、删除文件

import java.io.File;

public class Demo3 {
    public static void main(String[] args) {
        File f = new File("./test.txt");

        f.delete();
    }
}

4、创建目录


import java.io.File;

//创建目录
public class Demo4 {
    public static void main(String[] args) {
        File f  = new File("./testDir/aaa/bbb");
        f.mkdirs();
    }
}

(mkdir是创建单层目录,mkdirs是创建多层目录)

5、重命名文件

import java.io.File;

public class Demo5 {
    public static void main(String[] args) {
        //重命名
        File srcFile = new File("aaa.txt");
        File desFile = new File("bbb.txt");
        srcFile.renameTo(desFile);
    }
}

三、流(文件内容的操作)

java中提供了两种类来完成读写文件的操作。

 上述两种类因为是抽象类,所以有了后面的子类来实现读写需求!

1、InputStream.read() 字节流读文件


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

public class Demo7 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("./bbb.txt");
        while (true){
            int b = inputStream.read();
            if (b == -1){
                break;
            }
            System.out.println(b);
        }
        inputStream.close();
    }
}

                                  

2、outputStream.write() 字节流写文件

write中包含三个版本:

 

第一个是写一个字节;

第二个是把字节数组的所有内容,都写到文件中;

第三个是把b字节数组从下标off位置开始写,写len个字节。

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

public class Demo1 {
    //写文件
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("./bbb.txt");
        outputStream.write(97);
        outputStream.write(98);
        outputStream.write(99);
        outputStream.close();
    }
}

这里注意,使用outputStream写文件时,只要打开文件,就会把文件原有内容清空。

3、Reader 字符流读文件


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

public class Demo2 {
    public static void main(String[] args) throws IOException {
        Reader reader = new FileReader("./bbb.txt");
        while (true){
            int ret = reader.read();
//判断一下ret是不是-1,如果是,就是读完了
            if (ret == -1){
                break;
            }
            char ch = (char)ret;
            System.out.println(ch);
        }
        reader.close();
    }
}

ps:要注意read读到的是int类型,要用int类型来接收,最后打印时强转成char类型。

 4、Writer 字符流写文件


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

public class Demo3 {
    public static void main(String[] args) throws IOException {
        Writer writer = new FileWriter("./bbb.txt");
        writer.write("hello francis");
        writer.close();
    }
}

5、Scnner 字符流读文件

针对文本文件,使用字符流的时候,可以使用Scanner来读取。

InputStream是字节流。

Scnner是在InputStream的基础上,包装的字符流。

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

public class Demo4 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("./bbb.txt");
        Scanner scanner = new Scanner(inputStream);
        while (scanner.hasNext()){
            System.out.println(scanner.next());
        }
        inputStream.close();
    }
}

6、PrintWriter 字符流写文件

针对写文本文件来说,还可以使用PrintWriter来简化开发。

import java.io.*;

public class Demo5 {
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("./bbb.txt");
        PrintWriter writer = new PrintWriter(outputStream);

        writer.println();
        writer.printf("a = %d\n",10);
        outputStream.close();
    }
}

注意!

在进行文件操作时,一定要记得close!!!

每一个进程都对应着PCB,PCB里面有一个字段:文件表述符 表(同一个进程里多个PCB共同使用同一份文件描述符表的)

文件描述表相当于一个数组/顺序表。进程每次打开一个文件,就会在这个表里创建一个项。这个项就表示一个文件。

如果关闭一个文件,就会把表里的对应项给释放掉。

如果不关闭,这个项就会占着位置,如果你持续打开文件,且从来不关,这个表项就会被耗尽,导致后面再打开文件就会打开失败(文件资源泄露)!

所以上面的代码可以改一下

import java.io.*;

public class Demo5 {
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = null;
        try{
            outputStream = new FileOutputStream("./bbb.txt");
            PrintWriter writer = new PrintWriter(outputStream);

            writer.println();
            writer.printf("a = %d\n",10);
        }finally {
            outputStream.close();
        }


    }
}

这样,就算程序抛出异常,close也会执行到。


import java.io.*;

public class Demo5 {
    public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("./bbb.txt");){

            PrintWriter writer = new PrintWriter(outputStream);

            writer.println();
            writer.printf("a = %d\n",10);
        }

    }
}

也可以直接把OutputStream写道try里(try with resources,就是带资源的try)

把要关闭的对象写到try()里,当try结束时,就会自动调用对应对象的close方法。

四、结合实现个程序

1、扫描目录找到并删除

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

1、先让用户输入要扫描的路径+要查找的词

2、遍历目录,找到名字匹配的文件

遍历目录需要一个核心方法:

listFiles() 能够把当前目录里的文件和子目录列举出来,但是这个方法只能列出一层,所以解决方法是,遍历listFiles的结果,

        如果是普通文件,就直接判定文件名是否包含了要查的词

        如果是目录,递归调用listFiles

3、询问用户是否删除 

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

public class Demo6 {
    public static void main(String[] args) throws IOException {
        //1、先让用户输入要扫描的路径+要查找的词
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要扫描的路径");
        File rootDir = new File(scanner.next());
        if (!rootDir.isDirectory()){
            System.out.println("输入的目录不存在");
            return;
        }
        System.out.println("请输入要搜索的关键词");
        String toDelete = scanner.next();
        //2、遍历目录(rootDir),需要借助一个核心方法:listFiles。
        scanDir(rootDir,toDelete);
    }
    //递归遍历
    private static void scanDir(File rootDir, String toDelete) throws IOException {
        System.out.println("当前访问:"+ rootDir.getCanonicalPath());
        File[] files = rootDir.listFiles();
        if (files == null){
            //说明rootDir是个空目录
            return;
        }
        //如果目录非空,循环遍历每个元素
        for (File f:files){
            if (f.isDirectory()){
                scanDir(f,toDelete);
            }else {
                //不是空目录,普通文件,判定文件名是否符合要求,是否删除
                checkDelete(f,toDelete);
            }
        }
    }

    private static void checkDelete(File f, String toDelete) throws IOException {
        if (f.getName().contains(toDelete)){
            System.out.println("该单词"+ toDelete + "被" + f.getCanonicalPath() +"包含了,是否删除?(Y/N)");
            Scanner scanner = new Scanner(System.in);
            String choice = scanner.next();
            if (choice.equals("Y") || choice.equals("y")){
                f.delete();
            }
        }
    }

2、文件复制

把第一个文件打开,把里面的内容逐个字节读取出来,写到第二个文件就行。

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

//进行普通文件的复制
public class Demo8{
    public static void main(String[] args) {
        //1.先输入要复制哪个文件 和 将文件复制到哪里去(目标文件)
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入源文件:");
        //使用File的作用是可以判断文件是否存在
        File srcFile = new File(scanner.next());
        System.out.println("请输入目标文件:");
        File destFile = new File(scanner.next());
        if(srcFile.isFile()) {
            System.out.println("输入的源文件有误!");
            return;
        }
        //getParentFile()如果文件不存在就抛出异常
        if(!destFile.getParentFile().isDirectory()) {
            System.out.println("输入的目标文件有误!");
            return;
        }

        //2.打开源文件,按照字节读取内容,依次写入到目标文件中
        try(InputStream inputStream = new FileInputStream(srcFile);
            OutputStream outputStream = new FileOutputStream(destFile)) {
            //读 src 的每个字节,写入到 dest中
            while (true) {
                int ret = inputStream.read();
                //如果读到-1就结束
                if(ret == -1) {
                    break;
                }
                outputStream.write(ret);
            }
        }  catch (IOException e) {
            e.printStackTrace();
        }
    }
}

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

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

public class Demo7 {
    public static void main(String[] args) throws IOException {
        Scanner scanner  = new Scanner(System.in);
        System.out.println("请输入要扫描的路径");
        File rootDir = new File(scanner.next());
        System.out.println("请输入要查询的词");
        String toFind = scanner.next();
        
        scanDir(rootDir,toFind);
    }

    private static void scanDir(File rootDir, String toFind) throws IOException {
        File[] files = rootDir.listFiles();
        if (files == null){
            return;
        }
        for(File f : files){
            if (f.isDirectory()){
                scanDir(f,toFind);
            }else {
                checkFile(f,toFind);
            }
        }
    }

    private static void checkFile(File f, String toFind) throws IOException {
        //先检查文件名
        if (f.getName().contains(toFind)){
            System.out.println(f.getCanonicalPath() + "文件名包含" + toFind);
        }

        //检查文件内容
        try(InputStream inputStream = new FileInputStream(f)) {
            StringBuilder stringBuilder = new StringBuilder();
            Scanner scanner = new Scanner(inputStream);
            //读取
            while(scanner.hasNextLine()){
                stringBuilder.append(scanner.nextLine() + "\n");
            }
            if (stringBuilder.indexOf(toFind)>-1){
                System.out.println(f.getCanonicalPath()+"文件内容包含" + toFind);
            }
        }
    }
}

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值