JavaEE|IO、存储、硬盘、文件系统相关常识

IO、存储、硬盘、文件系统相关常识

计算机的硬件

处理器(CPU)、存储器(内存)、输入设备(Input Device)、输出设备(Output Device),后两者就被称为I/O

内存(Memory)又被称为RAM(Random Access Memory),支持O(1)时间复杂度,根据下标(内存地址)访问的存储

CPU只能和内存做直接的数据交换

Input Device:现实中的物理信号(光信号、电信号、波信号)转换为数字格式,存储在内存中

Output Device:将数字信号转化为物理信号

I/O设备包括:显示器(O)、触屏显示器(I/O)、鼠标(I)、键盘(I)、摄像头(I)、麦克风(I)、扬声器(O)

开发中接触得比较多得是:硬盘(I/O)、网卡(I/O)等

硬盘

既然要提到硬盘,那么存储得概念也必须要知道

image-20220628190404629

从内存往上的称为易失存储,硬盘往下的称为持久存储;

易失存储在断电后会丢失数据,以进程为单位管理;变量、对象本质上的编程语言对硬件中内存(易失存储)的抽象

持久存储断电后一般仍能保存,通常可以跨进程读写

各个存储访问速度的一个直观感受:

image-20220628190522269

硬盘(Hard Disk Drive - HDD)的实现:

  1. 磁盘 (利用磁性实现的一种存储方式),一般就指硬盘或者(机械硬盘)
  2. 固态硬盘 (Solid State Disk - SSD)
  3. 闪存 (Flash Memory)

image-20220628191207494

磁盘查找文件的步骤:

  1. 旋转盘片找到对应的扇区
  2. 找到对应的磁道

从磁盘的读取数据的过程中有许多物理操作,因此效率较低

并且磁盘更适合做连续数据的读写,而不适合做随机数据的读写

文件

软件层面认识硬盘中的数据:

硬盘可以分为两部分:「有数据存储的」和「暂时没有数据存储的(可用空间)」

有数据存储部分可以细分为数据1、数据2、数据3

每个数据又被抽象为文件1、文件2、文件3,可以说文件就是对硬盘中数据的抽象概念

因此硬盘数据的读写就是对文件的读写问题

主要由OS + 文件系统(FileSystem) 统一管理文件

我们看到的文件的基本知识:

  1. 文件被以树形结构(数据结构学的树,但不是二叉树)进行管理,文件都是树上的一个结点

  2. 文件可以大体分成两大类:

    • 存储数据的文件 - 普通文件(俗称的文件)
    • 管理树性结构组织数据的文件 - 目录/文件夹(directiry 或 dir) - 以/结尾,就代表这个结点是目录,比如C:/
  3. 这颗文件树只是逻辑结构,而不是硬盘上的物理结构

image-20220628192600335

无论是目录或者文件都只是树上的一个结点,一个结点可以有多个孩子

对于普通文件:

  1. 在Windows OS下,会以后缀名(file suffiex)来标记出这个文件存储的内容是什么内容,比如*.txt - 普通文本
  2. Windows下,我们可以将文件设置为可见或隐藏文件,建议把显示隐藏 + 显示扩展名都勾上

文件分为:目录、文本文件、不是文本的文件(二进制文件)

文本文件比如:*.txt以及*.java

不是文本的文件比如:*.class*.png

路径

关于文件路径(Path):

根据一个规则,从文件树上确定一个位置,这个位置一定对应到某个结点,但是这个结点可以不存在(路径只对应一个位置,但是该位置可以不存在该文件)

在Windows下,像C:/这种就称为根结点或者更多称为根目录

路径有两种:

  1. 绝对路径(absolute path - abs path):从一棵树的根结点处罚描述的路径,无论“我们”身处何处,总是能够唯一确定一个文件
  2. 相对路径(relative path):从“我们”所在的当前位置出发,描述的路径,“我们”的位置一变,路径就可能失效了

“我们”所在的位置一定是一个目录,而不能处于一个文件上的,首先找到我的父结点(Windows),再去到父亲结点

什么叫“我们”所在的位置:每个进程都有一个当前工作目录(current working directory - cwd),一般一个进程的启动目录,就是当前工作文件

image-20220628194010248

真实中如何去描述路径(重点):

Windows下,绝对路径例子:D:\课程\2022-06-27-火箭班-IO\板书.png

Mac下,绝对路径例子:/Users/harley/Desktop/code/FileTest/a

C:或者D:或者E:代表的就是根,这个以根开头的路径一定是个绝对路径,\/一般称为路径分隔符

“我们”身处D:\课程\/User/harley/Desktop/中:

Windows下,相对路径例子:\课程\2022-06-27-火箭班-IO\板书.png

Mac下,相对路径例子:/Desktop/code/FileTest/a

不是由根开始,所以是相对路径

在代码的字符串中如何表示这个路径

如果这么写:String path = "D:\课程\2022-06-27-火箭班-IO"是错误的

字符串中的反斜杠\表示转义的意思,因此应该写作:String path = "D:\\课程\\2022-06-27-火箭班-IO"

Windows使用\作为路径分隔符,Linux(Unix/XOS)使用/作为路径分隔符,不过Java是跨平台的,所以会自动帮我们处理这个问题,在代码中写\\或者/都可以,方便起见,可以使用/

因此可以这么写:String path = "D:/课程/2022-06-27-火箭班-IO"

路径表示中的两个特殊的符号:...

其中.表示在当前位置(目录)不动

其中..表示回到当前位置的父结点(目录)上,如果在根目录下使用该符号是没效果的,根没有双亲

这两个符号一般使用在相对路径中,假设我们还在桌面文件下:/Desktop/./code/../code/FileTest/

关于文件的路径的总结:

  1. 路径是树上找到一个结点的位置
  2. 路径并不表示文件一定存在
  3. 路径分为绝对路径和相对路径
  4. 当前位置:进程的当前工作目录
  5. 文件路径/或者\\表示路径分隔符,Java下使用哪个都可以

操作文件

普通文件只能是叶子结点,而目录文件既可以是叶子结点也可以是非叶子结点

在文件系统中,以结点为单元进行操作(在代码层面)

  • 文件移动操作(文件重命名、文件剪切 + 粘贴):结点的移动(重命名 or 移动到其他结点下)
  • 文件复制操作(复制 + 粘贴):新建结点 + 内容的复制
  • 目录移动操作(目录重命名、目录剪切 + 粘贴):以该结点为根的一颗子树的移动
  • 目录复制操作:以该结点为根的一颗子树的复制
  • 删除:默认情况下只能删除普通文件或空目录,只能删除结点,不能删除子树
  • 删除非空目录:对整棵树的删除

树的操作,需要转换成结点的操作:以目录的复制为例,遍历(深度 or 广度)整棵树,然后对其中的每个结点进行复制

通过代码操作文件

文件数据 = {元数据 + 内容数据}

与文件属性相关的数据是元数据或者管理数据,文件里的具体内容就是内容数据

接下来的学习中我们只关注元数据本身,暂时不管内容数据

比如对文件系统树的操作,判断是否存在,判断是否为目录,创建,删除,重命名等等

File类常用方法

在Java中通过File对象描述一个文件(结点,结点对应的文件是否存在不一定)

File类的构造方法:

public static void main(String[] args) {
    // 1. 绝对路径的方式创建
    // 1.1 直接传入字符串的路径即可
    File file1 = new File("/Users/harley/Desktop/code/FileTest/a/a.txt");
    // 1.2 传入父路径 + 子路径
    File file2 = new File("/Users/harley/Desktop/code/FileTest/b", "b.txt");
    // 1.3 以File传入 parent
    File parent = new File("/Users/harley/Desktop/code/FileTest");
    File file3 = new File(parent, "c.txt");
}

其他常用的方法:

  • int compareTo(File pathname):按字典序比较两个抽象路径名

  • public boolean createNewFile():当且仅当此的文件尚不存在时,才以原子方式创建一个以此抽象路径名命名的新的空文件

    返回true:创建成功

    返回false:创建失败(文件已经存在)

    抛出IOException:发生了IO异常(最常见的,是文件应该在的目录现在还不存在)

代码示例:

public static void main(String[] args) throws IOException {
    File file4 = new File("/Users/harley/Desktop/code/FileTest/d.txt");
    System.out.println(file4.createNewFile());// true
    System.out.println(file4.createNewFile());// false
}
// 第一次创建文件的时候成功了,后面因为文件已经存在因此不会再创建文件了

执行后的文件目录:

image-20220628213651025

如果在不存在的目录下创建文件,会发生什么情况:

image-20220628213935318

还有两个文件的创建方法:

  • public static File createTempFile(String prefix, String suffix):在默认临时文件目录中创建一个空文件,使用给定的前缀和后缀生成其名称
  • public static File createTempFile(String prefix, String suffix, File directory) :在指定目录中创建新的空文件,使用给定的前缀和后缀字符串生成其名称

删除方法:

  • public boolean delete():立即删除文件,只有当文件目录是正确的情况下删除成功并返回true,其他情况比如非空目录是无法删除的,回返回false
  • public void deleteOnExit():在JVM退出时才真正删除

删除单个文件的代码示例:

public static void main(String[] args) throws IOException {
    File file1 = new File("/Users/harley/Desktop/code/FileTest/d.txt");
    // 在d目录下创建一个文本文件 d.txt,然后再删除
    System.out.println(file1.createNewFile());// true
    System.out.println(file1.delete());// true
}

如果想要删除非空目录,先采用深度优先遍历,删除这个目录下的所有子孙,让这个目录变成空目录,然后再删除该目录

删除非空目录的代码示例:

public static void main(String[] args) throws IOException {
    File file = new File("/Users/harley/Desktop/code/FileTest/c/");
    // 删除c目录下的1目录
    traversal(file);
    file.delete();
}

private static void traversal(File dir) throws IOException {
    File[] files = dir.listFiles();// 查看这个目录下得所有孩子
    for(File file : files) {
        if(file.isDirectory()) {
            // 如果这个孩子也是个目录,就继续深度优先遍历
            System.out.println(file.getCanonicalPath() + "/");
            traversal(file);
            // 当深度优先遍历完成时,该目录为空,可删除
            file.delete();
        }else {
            System.out.println(file.getCanonicalPath());// 得到这个文件的一个标准路径(去除一切无意义的.和..)
            file.delete();
        }
    }
}

删除前,我们看看c目录下的所有文件

image-20220628222205634

由于是深度优先遍历所以一旦碰到目录,就先将碰到的目录遍历完再遍历自己目录中剩下的文件

去掉file.delete()的注释,执行代码,删除c目录下所有文件

image-20220628222921554

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值