bigywater.tech
Java · 356

FileStore:文件系统容量与属性

磁盘空间检查是个常见的小功能,但它的数字在不同文件系统上含义不同:稀疏文件、克隆、共享容器、只读挂载。这篇用真实挂载的小镜像,把 FileStore 返回什么、写满时发生什么逐项量出来。

19.5 → 0.5 MB
写满 20 MB HFS+ 卷时 usable 的变化;之后写入抛 No space left on device
0 vs −200.0 MB
APFS 克隆(cp -c)与普通 cp 复制 200 MB 文件对 usable 的影响
15
getFileStores() 返回的存储数,与 mount 输出的行数一致

getFileStore 读到什么

实测 · 本机执行输出
  [basic]
    APFS 数据卷上的临时目录:
        name=/dev/disk3s1 type=apfs readOnly=false block=4096 total=471482.1 MB usable=22332.2 MB unallocated=22332.2 MB
        属性视图:Basic=true Posix=true FileOwner=true Dos=false Acl=false UserDefined=true
        toString = /System/Volumes/Data (/dev/disk3s1)
    HFS+ 镜像(本次挂载):
        name=/dev/disk7s1 type=hfs readOnly=false block=4096 total=20.0 MB usable=19.5 MB unallocated=19.5 MB
        属性视图:Basic=true Posix=true FileOwner=true Dos=false Acl=false UserDefined=true
        toString = <实验目录> (/dev/disk7s1)
    FAT32 镜像(本次挂载):
        name=/dev/disk8s1 type=msdos readOnly=false block=512 total=63.0 MB usable=63.0 MB unallocated=63.0 MB
        属性视图:Basic=true Posix=true FileOwner=true Dos=false Acl=false UserDefined=true
        toString = <实验目录> (/dev/disk8s1)
    根目录 /:
        name=/dev/disk3s3s1 type=apfs readOnly=true block=4096 total=471482.1 MB usable=22332.2 MB unallocated=22332.2 MB
        属性视图:Basic=true Posix=true FileOwner=true Dos=false Acl=false UserDefined=true
        toString = / (/dev/disk3s3s1)
    Files.getFileStore("/etc")(符号链接,指向 private/etc):name=/dev/disk3s1 type=apfs readOnly=false block=4096 total=471482.1 MB usable=22332.2 MB unallocated=22332.2 MB
    不存在的路径:NoSuchFileException: /var/folders/km/b69gr9cs3dv8qsm8rjjb4qqc0000gn/T/fs12874453109841403756/nope
    同一个存储的两个对象 equals? true;tmp 与根目录的 store equals? false
  df -k 对照(1 KB 块):
    Filesystem     1024-blocks      Used Available Capacity iused      ifree %iused  Mounted on
    /dev/disk7s1         20440       476     19964     3%       2 4294967277    0%   <实验目录>
    /dev/disk8s1         64511         1     64510     1%       0          0     -   <实验目录>
    /dev/disk3s3s1   482797652  13756336  22868176    38%  484014  228681760    0%   /
    /dev/disk3s1     482797652 416448532  22868176    95% 3134703  228681760    1%   /System/Volumes/Data

getFileStores 列表

实测 · 本机执行输出
  [stores]
        / (/dev/disk3s3s1)                 type=apfs     readOnly=true  total=471482.1 MB
        /dev (devfs)                       type=devfs    readOnly=false total=0.2 MB
        /System/Volumes/VM (/dev/disk3s6)  type=apfs     readOnly=false total=471482.1 MB
        /System/Volumes/Preboot (/dev/disk3s4) type=apfs     readOnly=false total=471482.1 MB
        /System/Volumes/Update (/dev/disk3s2) type=apfs     readOnly=false total=471482.1 MB
        /System/Volumes/xarts (/dev/disk1s2) type=apfs     readOnly=false total=500.0 MB
        /System/Volumes/iSCPreboot (/dev/disk1s1) type=apfs     readOnly=false total=500.0 MB
        /System/Volumes/Hardware (/dev/disk1s3) type=apfs     readOnly=false total=500.0 MB
        /System/Volumes/Data (/dev/disk3s1) type=apfs     readOnly=false total=471482.1 MB
        /System/Volumes/Data/home (map auto_home) type=autofs   readOnly=false total=0.0 MB
        /System/Volumes/Update/SFR/mnt1 (/dev/disk2s1) type=apfs     readOnly=false total=5120.0 MB
        /System/Volumes/Update/mnt1 (/dev/disk3s3) type=apfs     readOnly=false total=471482.1 MB
        /Library/Developer/CoreSimulator/Volumes/iOS_23F77 (/dev/disk6s1) type=apfs     readOnly=true  total=17246.0 MB
        <实验目录> (/dev/disk7s1) type=hfs      readOnly=false total=20.0 MB
        <实验目录> (/dev/disk8s1) type=msdos    readOnly=false total=63.0 MB
    共 15 个 FileStore
  mount 命令的行数: 15

写满一个卷

实测 · 本机执行输出
  [fill]
    HFS+ 镜像(20.0 MB)写入前 usable = 19.5 MB
    循环写 40 个 1 MB:写入 19.0 MB;错误:IOException: No space left on device
    写满后 usable = 0.5 MB;文件 size = 19.0 MB;unallocated = 0.5 MB
    再创建一个小文件:<实验目录>
    删除后 usable = 19.5 MB
    预检查的陷阱:检查 usable = 19.5 MB 是否 >= 10 MB → true;但随后写 30 MB 仍会失败:IOException: No space left on device
    FAT32 镜像(63.0 MB)usable = 63.0 MB;写 10 MB 之后 usable = 53.0 MB

FAT32 与 HFS+

实测 · 本机执行输出
  [fat]
    FAT32 的属性视图:Basic=true Posix=true FileOwner=true Dos=false Acl=false UserDefined=true
    读取 posix 权限:rwx------(macOS 的 msdos 挂载在 Java 里仍能看到 posix 视图)
    用小写名字访问:Files.exists(hello.txt) = true;目录里的名字 = [t.bin, ._t.bin, Hello.TXT, ._Hello.TXT]
    创建符号链接:<实验目录>
    创建以冒号命名的文件 a:b → <实验目录>
    创建 300 字符长文件名 → FileSystemException: <实验目录> 个 x): File name too long
    文件修改时间的精度:写入时间 16921 ms;读回 lastModified % 2000 = 0(FAT 的时间戳 2 秒精度,取模为 0 说明已被截断到偶数秒)
    setLastModifiedTime(…001.123 s) 读回 1700000000000 ms
    对照 HFS+:setLastModifiedTime(…001.123 s) 读回 1700000001000 ms

稀疏文件与克隆

实测 · 本机执行输出
  [sparse]
    创建 2 GB 的文件(setLength)后:size = 2048.0 MB;usable 变化 0.0 MB(稀疏,没有分配)
    du -k 显示实际占用:0 KB
    写入 100 MB 随机数据后:size = 100.0 MB;usable 变化 -100.0 MB;du -k = 102400 KB
    删除 100 MB 文件后 usable 回升 100.0 MB
    200 MB 文件:cp -c(APFS 克隆)成功,usable 变化 0.0 MB;普通 cp 成功,usable 变化 -200.0 MB;三个文件 size 都是 200.0 MB / 200.0 MB / 200.0 MB
    改写克隆文件的前 50 MB 之后 usable 再变化 -49.9 MB(写时复制:只有被改写的部分才占新空间)

File 与 FileStore

实测 · 本机执行输出
  [file]
    File.getTotalSpace / getFreeSpace / getUsableSpace = 471482.1 MB / 22332.2 MB / 22332.2 MB;FileStore 的 total / unallocated / usable = 471482.1 MB / 22332.2 MB / 22332.2 MB
    不存在的路径:new File(nope).getFreeSpace() = 0(返回 0,不抛异常);Files.getFileStore(nope) → NoSuchFileException: /var/folders/km/b69gr9cs3dv8qsm8rjjb4qqc0000gn/T/fs14955048116493975500/nope
    根分区 / 的 usable = 22332.2 MB,Data 卷 /System/Volumes/Data 的 usable = 22332.2 MB,/System/Volumes/VM = 22332.2 MB
    getUsableSpace 与 getFreeSpace 差:0.0 MB(APFS 上两者相等,没有为非特权用户另外保留空间)
    同一个 APFS 容器里不同卷共享空闲空间:Data 卷 unallocated = 22332.2 MB,VM 卷 unallocated = 22332.2 MB,根(/)= 22332.2 MB

只读挂载

实测 · 本机执行输出
  [ro]
    只读挂载的 HFS+:isReadOnly = true;usable = 19.5 MB;total = 20.0 MB
    写文件:FileSystemException: <实验目录> Read-only file system
    创建目录:FileSystemException: <实验目录> Read-only file system
    删除已有文件:FileSystemException: <实验目录> Read-only file system
    读已有文件:hello
    Files.isWritable(dir) = false(只读文件系统上返回什么)
    根卷 /:isReadOnly = true;写 /x.txt → FileSystemException: /x.txt: Read-only file system
  收尾:镜像已卸载? True

分步演示

FileStore
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS APFS 数据卷;HFS+ 与 FAT32 磁盘映像由 hdiutil 在本实验中创建、挂载,实验结束后已卸载并删除;空间数字有磁盘上其它进程的小幅干扰
    • 没有验证:Linux 上 ext4 / XFS / tmpfs 的 FileStore(没有 Linux 环境)、网络文件系统(NFS / SMB)、磁盘配额下 getUsableSpace 的含义、Windows 的 FileStore(含 volume 属性)、exFAT / NTFS、getUsableSpace 与 getUnallocatedSpace 在有 root 保留块的文件系统上的差别
    京ICP备2026067502号-1京公网安备11010502063487号