IO、存储、硬盘、文件系统详细总结

1. 底层硬件:硬盘

硬盘是持久化 I/O 硬件设备,分为机械硬盘 HDD、固态硬盘 SSD。 硬盘硬件层面由大量扇区组成,扇区是硬件最小读写单元(常见 512B/4KB)。硬盘本身只是一堆扁平的二进制块,硬件上没有 "文件、文件名、文件夹" 这些概念 。操作系统需要一套软件规则,把磁盘上原始扇区组织成我们使用的文件,这套规则就是文件系统 。

2. 文件系统核心概念

2.1 文件:数据 + 元信息

文件分为两部分:

  1. 文件内容(数据):真正保存业务数据。
  2. 元信息(元数据 metadata):不属于文件内容,描述文件属性:文件名、大小、修改时间、权限、类型等。

硬盘会分别存储文件数据内容和文件元信息。

注意:目录(文件夹)本身也是一种特殊文件,目录文件内部保存的就是一批文件的元信息映射关系,用来管理下属文件 / 子目录。

2.2 树形目录结构

文件数量变多之后,文件系统使用树形结构组织全部文件。根节点出发不断分支,节点可以是普通文件,也可以是目录。

  • Windows:多棵树,每个磁盘分区一个根,例如C:\;
  • Linux:单根树,只有一个根/,磁盘分区通过挂载接入这颗大树。

目录的作用就是管理子节点,让大量文件逻辑清晰、方便用户定位使用。

2.3 文件路径

径用来在树形文件树上唯一定位一个文件,分为两种:

  1. 绝对路径 :从根节点开始完整描述路径。Windows 示例:C:\Program Files\test.txt;Linux:/home/user/test.txt。
  2. 相对路径 :从当前工作目录 出发定位文件;.代表当前目录,..代表父目录。

不同系统路径分隔符不一样:Windows 使用\,Linux 使用/,Java File类提供pathSeparator自动适配系统分隔符。

2.4 文件类型、权限、链接

1.文本文件 vs 二进制文件

  • 文本文件: 内容是经过字符集编码的字符;
  • 二进制文件: 按自定义格式存储,没有字符编码含义(图片、exe 程序)。

Windows 依靠后缀名识别文件类型;Linux/Unix 不依赖后缀名识别文件类型。

2.文件权限:可读、可写、可执行,操作系统依靠权限机制保护数据安全,没有权限的用户不能做对应操作。

3.链接:Windows 快捷方式、Linux 软链接,本质是对真实文件的引用。

4.Unix/Linux 设计思想:万物皆文件,把磁盘、网卡、键盘显示器各类 I/O 设备全部抽象成文件,统一一套接口操作设备和普通磁盘文件。

2.5 文件系统做了什么总结

裸磁盘只有扇区;文件系统是一套软件规范:

  1. 在磁盘块上保存文件数据、元信息;
  2. 维护树形目录,维护文件名到文件实体的映射;
  3. 提供路径定位文件;
  4. 管理权限;
  5. 向上给应用程序提供打开、读、写、删除、创建目录等操作接口。

3. IO 的概念

IO 就是输入输出,程序和存储设备之间传输数据。课件用水池比喻 IO:

  • 输入流(读):从文件读取数据到程序,如同从水池接水;
  • 输出流(写):把程序的数据写入文件,如同向水池灌水。

缓冲区:IO 硬件速度慢,输出流会先把数据暂存内存缓冲区,缓冲区满才真正写磁盘。flush()强制把缓冲区数据刷入磁盘,避免数据留在内存丢失。

4. Java 对文件系统、IO 的封装

4.1 java.io.File 类

File类用来抽象描述一个文件 / 目录的路径。

⚠️创建 File 对象≠磁盘上真实存在这个文件,只是内存中的路径描述。

用核心方法:

表格

方法 作用
exists() 判断文件 / 目录磁盘上是否真实存在
isFile() / isDirectory() 判断是普通文件还是目录
createNewFile() 创建空普通文件
delete() 立刻删除文件;deleteOnExit()JVM 退出才删除
mkdir() 创建单级目录;mkdirs()创建多级嵌套目录
listFiles() 获取目录下所有子文件 File 对象
getAbsolutePath() / getCanonicalPath() 获取绝对路径,canonic

4.2 字节流: InputStream / OutputStream

针对原始字节读写,所有文件底层都是字节:

  1. FileInputStream 文件输入流:读文件字节;
    • read():读 1 个字节;
    • read(byte[] buf):读到字节数组,批量读,减少 IO 系统调用,性能更好;
    • 返回-1代表读到文件末尾;
  2. FileOutputStream 文件输出流:写文件字节;
    • write()系列写入字节 / 字节数组;
    • 必须flush()刷新缓冲区 ;
  3. 流需要关闭释放资源,课件全部使用try‑with‑resources语法,自动执行 close,避免资源泄露。

4.3 字符读写

直接用字节流处理中文文本很麻烦(需要手动处理 UTF‑8 编码):

  1. Scanner(InputStream, charset) :方便按字符读取文本;
  2. OutputStreamWriter :字节流转字符流,指定字符集;
  3. PrintWriter :包装后支持print / println / printf,写文本非常方便,写完记得flush()。

4.4 典型 IO 代码示例

  • 读文件范式(字节批量读)
java 复制代码
try (InputStream is=new FileInputStream("test.txt")){
            byte[] buf=new byte[1024];
            int len;
            while ((len=is.read(buf))!=-1){
                //本次读到的为有效字节
            }
        }
  • 写文件范式
java 复制代码
try (OutputStream os=new FileOutputStream("out.txt");
             //字节->字符的转换器
        OutputStreamWriter osw=new OutputStreamWriter(os,"UTF-8");
        PrintWriter pw=new PrintWriter(osw)){
            pw.println("测试内容");
            pw.flush();
        }

基于上面 API,可以实现:递归遍历目录、文件复制、查找文件名包含关键字的文件、检索文件内容关键字等小工具。文件系统是树形,扫描目录一般用深度优先递归遍历。

6. 总结

硬盘只是物理存储硬件,本身没有文件概念。文件系统是操作系统最重要抽象之一 :把冰冷磁盘扇区抽象为文件、目录、路径、权限。 IO 就是数据的流入流出;Java 中File负责描述文件元信息与路径,字节流、字符流负责文件内容读写。

"万物皆文件" 的思想,就是借助文件系统的抽象,把普通磁盘文件、硬件设备统一成同一套 IO 接口,极大简化上层应用开发。

相关推荐
SL_staff3 小时前
设备离线时业务不中断:JVS-IOT高可用架构解析
java·物联网·产品
郭小李3 小时前
mybatis 动态 sql
java·sql·mybatis
瑞码空间3 小时前
JSP与Servlet核心开发与CRUD实战笔记
java·笔记·servlet·jsp
知守观3 小时前
技术考古:iBATIS 2.3.4 时代的持久层,是如何用 Map 玩转 307 个存储过程的?
java·后端·mybatis
captain3764 小时前
MyBatis Plus(1)
java·服务器·mybatis
香蕉大香蕉(06敬畏市场)4 小时前
MySQL 单点详解(08)
java·数据库·mysql·面试·八股
thefool1122664 小时前
HTTPS协议
java
acd120095 小时前
Nginx 反向代理的缓冲区坑:后端响应大时接口偶发 502
java·运维·nginx
装不满的克莱因瓶5 小时前
支付订单成功异步MQ权益发放设计和开发
java·架构·系统架构·rabbitmq·硬件架构