[11]从零开始的JAVAEE-文件操作和IO

目录

前言

一、什么是文件操作

硬盘(外存)内存的区别

绝对路径和相对路径

文本文件和二进制文件

判定方式

二、文件系统操作

 File类的构造方法

  File类的方法

使用file类创建文件

使用file类创建目录

列出一个目录下所包含的内容

 三、文件内容操作

InputStream使用方法


前言

在前十章中,介绍了多线程的一些操作,从第十一章开始,会进行第二个部分的讲解:文件IO操作,这也是JAVAEE中一个非常重要的板块,但难度相比较于多线程会简单许多。

一、什么是文件操作

硬盘(外存)内存的区别

  • 速度:内存比硬盘快很多
  • 空间:内存比硬盘空间小很多
  • 成本:内存比硬盘贵很多
  • 持久化:内存断电后数据消失,外存断电后数据还在

在JAVASE、数据结构这些板块中,主要操作的是内存,而MySQL和这里的文件操作,主要操作的就是外存。

绝对路径和相对路径

在系统中,文件通常是以N叉树的结构来组织的

 如果我们需要系统中找一个文件,则需要通过遍历这颗树的方式来进行查找。

  • 绝对路径:从盘符开始,一层一层往下找,得到的路径叫做绝对路径
  • 相对路径:从给定的某个目录触发,一层一层往下找,得到的路径叫相对路径

查找时一定要明确基准目录是什么,假设此时工作目录是这个此时需要找到

相对路径:以工作目录为基准,往下找一层

 此时就找到了README这个文件

表示为./MySQL Server 5.7/README

绝对路径则是C:\\Program Files\\MySQL\\MySQL Server 5.7\\README

(“\\”相当于一个“/”,转义字符)

  •  .是一个特殊符号表示为当前目录
  • ..表示当前目录的上级目录

如果要查找的文件在工作目录的上一级,那就表示为:../README

文件系统上,任何一个文件对应的路径都是唯一的,不会存在两个路径相同但是文件不同的情况,在Linux上可能存在一个文件有两个不同的路径的情况,但在Windows上文件和路径都是一一对应的

文本文件和二进制文件

  • 文本文件:存储文本(ASCII码值或utf8之类的字符集编码)
  • 二进制文件:存储二进制数据

判定方式

直接使用记事本打开某个文件,如果你看得懂就是文本文件,如果是一堆乱码就是二进制文件,这是因为记事本默认是使用文本文件的打开方式读取文件的。

二、文件系统操作

在JAVA标准库中提供了File这个类,来操作硬盘

File对象是硬盘上的一个文件的抽象表示:因为文件存储在硬盘上,直接使用代码操作硬盘是不方便的,所以可以在内存中创建一个对应的对象,通过操作这个对象来影响改变硬盘中的数据

 File类的构造方法

  File类的方法

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

public class iodemo1{
    public static void main(String[] args) throws IOException {
        //1.构造File对象
        File file = new File("d:/cat.jpg");//这个路径可以存在也可以不存在,我这里不存在
        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());//修饰过的绝对路径,需要抛出IOException异常
    }
}

这段代码中构造了一个File对象,我们可以调用一些方法来看一看结果

在构造File时我填的是绝对路径,现在修改为相对路径来看一下结果

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

public class iodemo1{
    public static void main(String[] args) throws IOException {
        //1.构造File对象
        File file = new File("./cat.jpg");//这个路径可以存在也可以不存在,我这里不存在
        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());//修饰过的绝对路径,需要抛出IOException异常
    }
}

可以看到,如果填入相对路径,这里的工作路径就会被识别为当前代码所处路径。 也就是这段代码在你的电脑中所处的路径。

使用file类创建文件

    public static void main(String[] args) throws IOException {
        File file = new File("./hello_world.txt");
        System.out.println(file.isDirectory());//是不是一个目录
        System.out.println(file.isFile());//是不是一个文件
        System.out.println(file.isAbsolute());//是不是绝对路径
    }

这段代码中构建了一个file对象在文件中,此时文件中是没有hello_world这个文件的,所以它不是目录不是文件不是绝对路径,输出结果则为:

 我们可以把这个文件创建出来,然后看结果

    public static void main(String[] args) throws IOException {
        File file = new File("./hello_world.txt");
        System.out.println(file.isDirectory());//是不是一个目录
        System.out.println(file.isFile());//是不是一个文件
        System.out.println(file.isAbsolute());//是不是绝对路径
        
        file.createNewFile();//创建文件
        System.out.println();

        System.out.println(file.isDirectory());//是不是一个目录
        System.out.println(file.isFile());//是不是一个文件
        System.out.println(file.isAbsolute());//是不是绝对路径
    }
}

 文件被创建出来,由于构建file对象时使用的是相对路径,所以文件被创建在代码存储目录下

这里的hello_world就是被创建的文件。

使用file类创建目录

  • mkdir():构建一个单级目录
  • mkdirs():构建一个多级目录
public class iodemo3 {
    public static void main(String[] args) {
        File file = new File("test_dir");
        file.mkdir();
    }
}

这里使用file类构建了一个test_dir对象,然后使用mkdir构建一个单级目录,运行后左侧会出现一个名为test_dir的目录

public class iodemo3 {
    public static void main(String[] args) {
        File file = new File("test_dir/aaa/bbb");
        file.mkdirS();
    }
}

这里使用file类构建了一个test_dir对象,然后使用mkdirs构建一个多级目录,运行后左侧会出现一个名为test_dir的多级目录

列出一个目录下所包含的内容

  • list() 方法返回一个String数组,包含指定目录下所有文件和子目录的名称,但不包括子目录中的内容。

  • listFiles() 方法返回一个 File 类型的数组,包含指定目录下所有文件和子目录的 File 对象,但不包括子目录中的内容。

为了方便区分我在test_dir目录下创建了一些文件

public class iddemo4 {
    public static void main(String[] args) {
        File file = new File("test_dir");
        String[] a = file.list();
        System.out.println(Arrays.toString(a));
        File[] b = file.listFiles();
        System.out.println(Arrays.toString(b));
    }
}

 三、文件内容操作

  •  针对文本文件,JAVA标准库提供了一组类,统称为“字符流”(Reader,Writer),读写的基本单位是字符
    •  针对二进制文件,JAVA标准库提供了一组类,统称为“字节流”(InputStream,OutputStream),读写的基本单位是字节

流:这是一个比较抽象的概念,我们将文件中的内容称为流,这样在读取数据时,如果有100个字节的数据,我们可以分两次每次读50个,也可以分5次每次读20个,或者分10次每次读10个......通过流我们可以自由的读取数据

InputStream使用方法

public class iodemo5 {
    public static void main(String[] args)throws IOException {
        InputStream inputStream = new FileInputStream("d:/test.txt");
        inputStream.close();
    }
}

由于InputStream是一个抽象类,不能直接实例化,所以需要实例化基础了这个抽象类的子类FileInputStream。

文件打开以后一定要记得关闭!!!否则会出大问题

在JAVA中内存是不需要手动释放的,因为在JVM有一个GC资源回收机制,会自动进行内存的释放,而文件资源是没办法自动释放的。在每个进程中,会使用PCB来描述,在PCB中又存在一个文件描述符表,在这个表中,每打开一个文件,表中就会申请一个位置将文件放到这个表中,但是这个表是长度是有限的,如果在关闭文件之后没有进行释放,那么在程序运行过程中,可能会导致这个表的空间被占用满了,后续文件打开时无法在这个表中申请到空间,从而导致打开文件失败,这会导致很严重的问题!

为了解决这个问题,我们可以使用这样一种语法来预防忘记执行close操作的情况

public class iodemo5 {
    public static void main(String[] args)throws IOException {
        try(InputStream inputStream = new FileInputStream("d:/test.txt");) {

        }
    }
}

我们将这个语法称为try with resoures:带有资源的try操作,这个语法会在try代码块结束时,自动执行close操作

在创建完inputstream流对象后,我们通过这个对象来读取文件中的内容,此处我读取的文件是d盘的test.txt文件,我已经提前创建好了,文件中的内容为:

 下面可以通过read()方法来读取文件,需要注意的是:

read()方法的返回值是int类型而不是byte类型

这是因为byte的值域为0-255,而read()方法在文件读到末尾时会返回一个-1,这并不在byte的值域内,所以可以干脆将返回值设置为int类型,在需要处理数据时,在将其转为byte即可,如果是-1,将会转换失败,从而标记文件读到了末尾。

public class iodemo5 {
    public static void main(String[] args)throws IOException {
        try(InputStream inputStream = new FileInputStream("d:/test.txt");) {
            while (true){
                int b = inputStream.read();
                if(b == -1){
                    //读到末尾,return
                    break;
                }
                System.out.println(b);
            }
        }
    }
}

结果为: 

 这是一组ASCII码数据,对应这些ASCII码可以将其转换为对应的数据。因为文件中存储的内容为中文,所以会使用utf8字符集来表示数据,在utf8中,一个汉字=3个字节,这里读出了21个ASCII码,也就是21个字节,7个汉字。

还可以使用OutputStream中的write方法来进行数据写入

public class iodemo5 {
    public static void main(String[] args)throws IOException {
        try(OutputStream outputStream = new FileOutputStream("d:/test.txt");) {
                outputStream.write(97);
                outputStream.write(98);
                outputStream.write(99);
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不卷啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值