文件操作和IO

目录

路径

文本文件和二进制文件

文件操作

1.文件系统操作

(1)构造一个File对象

 (2)File提供的一些方法

(3)文件内容操作(读写操作)

 字节流 —— InputSteam使用

 1.close()(重要)

 2.无参数read()读操作

 3.write()写操作

字符流 —— Reader(与字节流相似)

1.read()操作

 2.write操作

 使用文件操作实现一个案例


文件,一般指的都是硬盘上的文件。

硬盘(外存)内存相比,速度上,内存比硬盘快很多,空间上,内存空间比硬盘小,成本上,内存比硬盘贵,数据的持久化存储,内存掉电后数据丢失,外存掉电后数据还在。

javaSE + 数据结构,定义变量都是在内存上申请空间,MySQL是操作硬盘

文件IO是操作硬盘操作。

路径

绝对路径:从盘符(此电脑)开始,一层一层往下找,这个过程,得到的路径。

相对路径:从给定的某个目录出发,一层一层往下找,这个过程得到的路径,一定要明确,基准目录是什么。

./:"."表示当前目录

../:".."表示当前目录的上级目录

windows文件系统上,任何一个文件,对应的路径是唯一的。

windows上可以认为,路径和文件是一一对应的,相当于一个文件的”身份标识“。

文本文件和二进制文件

文本文件,存储的是文本,文本文件就是由ASCII字符或者其他字符集编码(utf8这种)所得到的文件。

二进制文件存储的是二进制数据,没有任何字符集的限制,存储什么都行,比如.class和.exe文件就是二进制文件。

使用记事本(默认是按照文本的方式来解析显示的)打开某个文件,如果是可以看懂的文件,就是文本文件,如果是乱码,就是二进制文件。

文件操作

文件操作分为:

1.文件系统操作

创建文件,删除文件,重命名文件,创建目录

关于文件系统操作,java标准库,给我提供了一个叫做File的类。File对象是硬盘上的一个文件的”抽象“表示。

文件是存储在硬盘上的,直接通过代码操作硬盘,不太方便,就在内存中创建一个对应的对象,操作这个内存中的对象,就可以间接影响到硬盘中的文件情况了。

java中使用File类:

(1)构造一个File对象

构造过程中,可以使用绝对路径/相对路径进行初始化,这个路径指向的文件,可以是真是存在的,也可以是不存在的。

public static void main(String[] args) {
        //通过File对象进行操作
        File file = new File("d:/cat.jpg");//使用反斜杠
    }

 (2)File提供的一些方法

 一些方法使用介绍:

createNewFile()和delete()

 public static void main(String[] args) throws IOException {
        File file = new File("./hello_word.txt");
        System.out.println(file.exists());//判断file对象是否存在
        System.out.println(file.isDirectory());//判断file对象代表的文件石佛偶是一个目录
        System.out.println(file.isFile());//判断file代表的对象是不是一个普通文件

        //创建文件
        file.createNewFile();
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());

        //删除文件
        file.delete();
        System.out.println("删除文件之后");
        System.out.println(file.exists());
    }

mkdir()和mkdirs()

public static void main(String[] args) {
        File file = new File("test-dir/aaa/bbb");
        //file.mkdir()只能创建一级目录
        file.mkdirs();//创建多级目录
    }

file.list()和file.listFiles()

 public static void main(String[] args) {
        File file = new File("test-dir");
        //列出目录下有哪些内容
        String[] results = file.list();
        System.out.println(Arrays.toString(results));
        File[] results2 = file.listFiles();
        System.out.println(Arrays.toString(results2));
    }

 renameTo()重命名操作

public static void main(String[] args) {
        //重命名
        File src = new File("./test-dir");
        File dest = new File("./test222");

        src.renameTo(dest);
    }

2.文件内容操作(读写操作)

针对文件内容进行读和写.

路径:文件系统上的一个文件/目录的具体位置。

目录 = 文件夹

计算机的目录是有层级结构的,文件系统时以树型结构来组织文件和目录的,是一个N叉树。

文件路径,就是从树根节点出发,沿着树杈,一路向下,到达目标文件的经过的内容。

windows都是从“此电脑”起头的,表示路径的时候,可以把“此电脑“省略,直接从盘符表示开始。

针对文本文件,提供了一组类,统称为”字符流“(典型代表,Reader,Writer),读写的基本单位是字符

针对二进制文件,提供了一组类,统称为”字节流“(典型代表,InputStream,OutputStream),读写的基本单位是字节

字节流和字符流:比如从文件读取100个字节,可以一次性读完,也可以分着读,像接水一样,所以称为”流“。

每种流对象,分为两种:

输入的:Reader(字符流),InputSteam(字节流)

输出的:Writer(字符流),OutputStrea(字节流)

以CPU为视角,描绘输入输出:

 字节流 —— InputSteam使用

  InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本 可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用 FileInputStream(InputStream inputStream = new FileInputStream())

 1.close()(重要)

public static void main(String[] args) throws IOException {

        //从文件读取
        InputStream inputStream = new FileInputStream("d:/text.txt");

        //关闭操作,很重要
        inputStream.close();
    }

关于inputStream.close()为什么重要:

首先文件里的资源,是文件描述符,关于文件描述符表,这样理解:

文件描述符表:文件描述符表记录了当前进程都打开了哪些文件,每次大家一个文件,都会在这个表里里面申请到一个位置,这个表可以当成一个数组,数组下标就是文件描述符,数组元素就是这个文件在内核中的结构体的表示。

但是这个文件描述符表的长度是有限制的,不能无休止的打开不释放,一旦满了,继续打开打开就会失败。

此时每次从文件读取内容以后,我们就需要使用inputStream.close()关闭释放资源,因为这个文件描述符表一旦满了,继续打开就会打开失败(这个问题称为文件资源泄露),很严重,如果工作时造成这个事故,可能会给个人以及公司带来损失。

所以为了避免这个close()没有写,我们可以写如下操作:

public static void main(String[] args) throws IOException {
        //try with resources带有资源的try操作,
//会在try代码块结束,自动执行close关闭操作
        try(InputStream inputStream = new FileInputStream("d:/text.txt")){

        }
    }

这里会自动关闭是因为InputStream底层实现了一个Closeable接口:

 2.无参数read()读操作

关于无参数read(),每一次读都是一个字节,返回值为int.

返回值为int原因如下:

 大致意思就是因为byte类型表示的范围是0 -> 255(有时候是-128 -> +127),如果读取完毕,到头了,再次read就会返回-1,由于-1在0 -> 255 范围之外,所以这里取的返回值为int.这是我的文件里的文字:

public static void main(String[] args) throws IOException {
        //try with resources带有资源的try操作,会在try代码块结束,自动执行close关闭操作
        try(InputStream inputStream = new FileInputStream("d:/text.txt")){
            //无参数的read()默认会返回一个字节,返回值类型是int
            while (true) {
                int b = inputStream.read();
                if (b == -1) {
                    //读到末尾,结束循环
                    break;
                }
                System.out.println(b);//以字节流输出
            }
        }
    }

这是我的文件里的文字:

 读入后以字节流输出(ASCII表值对应,如果文件里面是汉字,就会以字符集里面的标准输出,一般是utf8):

 3.write()写操作

在文件里面写入abc:

public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("d:/test.txt")) {
            //写入字节
            outputStream.write(97);//a
            outputStream.write(98);//b
            outputStream.write(99);//c
        }
    }

运行结果:

关于read()和write(),可以一次性读写多个字节,使用byte[]来表示,

read(),会尽可能把byte[]填满,

write,会把byte[]中所有数据都写入文件。

字符流 —— Reader(与字节流相似)

1.read()操作

public static void main(String[] args) {

        try(Reader reader = new FileReader("d:/test.txt")) {
            while (true) {
                int c = reader.read();
                if (c == -1) {
                    break;
                }
                char ch = (char)c;//字符int -> char
                System.out.println(ch);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

运行结果:

 2.write操作

try(Writer writer = new FileWriter("d:/test.txt")) {
            writer.write("a");
        }catch (IOException e) {
        e.printStackTrace();
        }

 使用文件操作实现一个案例

查找某个词出现在哪些文件里,返回该文件绝对路径,代码如下:

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

public class IODemo9 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入您要查找的目录");
        //1.先让用户指定一个要搜索的根目录
        File rootDir = new File(scanner.next());
        if (!rootDir.isDirectory()){
            System.out.println("输入有误,您输入的目录不存在");
             return;
        }
        //让用户输入一个要查询的词
        System.out.println("请输入一个要查询的词");
        String word = scanner.next();

        //3.递归的方式进行目录/文件的遍历
        scanDir(rootDir,word);
    }
    private static void scanDir(File rootDir,String word) {
        //列出当前的rootDir中的内容,没有内容,直接递归结束
        File[] files = rootDir.listFiles();
        if (files == null) {
            //当前rootDir是一个空的目录
            //没有必要递归了
            return;
        }
        //目录里面有内容,就便利目录中的每个元素
        for (File f : files) {
            System.out.println("当前搜索到:" + f.getAbsolutePath());
             if (f.isFile()) {
                 //如果是普通文件
                 //打开晚间,读取内容看是否包含上面的关键词
                 String content = readFile(f);
                 if (content.contains(word)) {
                     System.out.println(f.getAbsolutePath() + "包含要查找的关键字");
                 }
             }else if(f.isDirectory()) {
                 //是目录
                 scanDir(f,word);
             }else {
                 //既不是普通文件也不是目录,直接跳过
                 continue;
             }
        }
    }

    private static String readFile(File f) {
        //读取文件的整个内容,返回
        //使用字符流读取,因为匹配的是字符串,直接按照字符流处理
        StringBuilder stringBuilder = new StringBuilder();
        try (Reader reader = new FileReader(f)){
            //一次制度一个字符,把督导的结果给拼装到StringBuilder中,统一转成String
            while(true) {
                int c = reader.read();
                if (c == -1) {
                    break;
                }
                stringBuilder.append((char)c);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值