V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
mythmgn
V2EX  ›  Python

Python 踩坑之旅文件系统篇其一文件夹也是 File Object

  •  
  •   mythmgn · 2019-09-23 10:26:09 +08:00 · 2736 次点击
    这是一个创建于 1914 天前的主题,其中的信息可能已经有所发展或是发生改变。

    1.1 案例

    这期案例讲的是 Unix-Like 系统中, 常听到的一句话: 目录也是个文件 或者 everything is a file. 和 Python 踩坑联系不紧密, 目标是方便大家理解 文件夹以及文件 在 类 Unix 系统上的读写方式.

    刚接触 Linux 文件系统的同学有时候听到这个很懵, 目录怎么是个文件呢?目录不应该是内部包含文件的载体么?

    1.2 分析

    分析主要从 2 个方面展开:

    • ls 实际是使用大量文件系统标准接口实现的结果, 是处理过后的用户程序
    • 从文件系统的组织结构来看穿数据存储和读写方式

    如果大家已习惯了 Linux 系统中 ls 命令 (有时候由于alias 存在, 实际是ls --color), 容易产生一种错觉:文件夹和文件这不是天然的被区分为不同的类别了吗?

    • 比如蓝色的文件夹?
    • 黑色的文件?`

    实际不是这样子的, ls mkdir touch 一类的文件系统操作命令其实是通过调用文件系统接口实现的用户态程序, 你自己利用 python 也可以实现一个一摸一样的.

    我们来看一些使用 python 访问文件系统的简单例子:

    from __future__ import print_function  
    import os
    
    # 简单文件写
    with open('./test', 'w+') as fhandle:
        fhandle.write('test\n')
    
    # 创建文件夹
    
    dirname = os.path.abspath('./test_dir')
    if not os.path.exists(dirname):
        os.makedirs(dirname)
    
    for ind in range(0, 10):
        with open('{0}/test_file_{1}'.format(dirname, ind), 'w+') as fhandle:
            fhandle.write('1')
        dname = '{0}/test_dir_{1}'.format(dirname, ind)
        if not os.path.exists(dname):
            os.mkdir(dname)
    
    # 读文件夹
    for obj in os.listdir(dirname):
        objpath = os.path.join(dirname, obj)
        if os.path.isfile(objpath):
            print('{0} is a file'.format(objpath))
        elif os.path.isdir(objpath):
            print('{0} is a dir'.format(objpath))
    

    因此, 大家理解 ls 类耳熟能详的 Linux 命令是经过代码实现的用户程序, 如果你想且有时间完成可以实现一个 python 版 的ls


    更进一步的说, 对文件或者文件夹的操作本质上是用户层的代码实现调用了系统相关的接口. 这代表着文件夹和文件对系统来讲, 就是数据组织上的不同 (数据结构的不同). 那数据或者文件数目是怎么进行组织的?

    想了解这个问题就要先了解 Linux 系统上的文件存储层次, 以在 Linux 上挂载的文件系统进程读写为例:

    • 最上层, 用户的程序进程 Process, 通过调用类似 open write close 等通用系统函数读写所在挂载目录的文件

    • 中间 Kernel VFS (Virtual Filesystem, 虚拟文件系统)

      • 市面上主流的文件系统并不少, 为了让上层应用不关心如何读写这些内部实现各异的文件系统, Kernel 实现了虚拟文件系统
      • 虚拟文件系统包含一系列的标准;
        • 为了方便理解, 可以简化理解为提供了一系列读写接口标准
        • 上层用户应用使用下层的文件系统不需要关心你是哪个文件系统, 我只要挂载好你到我的系统就能使用标准接口读写
    • 底层, Kernel 内核, 各个设备厂家不同的 VFS 实现嵌入 kernel 中以支持具体的读写等操作

    • 物理介质层 (块设备等), 真正的硬件设备层

    而我们要聚焦到 VFS 这层来看, 因为它:

    1. 屏蔽下层不同设备厂商数据存储实现
    2. 抽象并统一了数据存储接口

    只要明白了它如何组织文件 /文件夹, 基本上就明白了人们常说 everything is a file 的意思.

    具体到数据结构上, 要看虚拟文件系统上规定了针对文件系统的 4 类数据结构:

    • superblock
      • 用来存储挂载的文件系统的元信息 (比如 inode 数目等)
      • 简化理解起来就像是文件系统的索引系统, superblock 决定了如下几个数据结构的分布
    • inode, 用来存储具体数据的单元 (包括人们通常理解的 file 实体和文件夹)
    • dentry, directory entry, 用来描述文件夹信息
    • file obj, 进程打开文件描述

    对 VFS 来讲, 无论是存储了具体字节数据的文件, 还是文件夹, 本质都是个 inode 作元信息描述的逻辑结构.

    无非文件夹不包括具体数据信息描述, 但包含一些指针 (指向该文件夹包含的一系列数据文件或者子文件夹). 相反, 一个指向数据的 inode 不包含子目录或文件们.

    1.3 扩展

    基本了解了文件系统的组织方式后, 留几个问题大家给大家做扩展思考?

    1. 通常我们说一个文件系统满盘了, 可能扩展哪几种满盘?
    2. 我只创建文件夹但不创建文件, 文件系统会满盘么?
    3. 文件系统有时候出现错乱, 需要进行 fs check, 这个时候可能是什么坏掉了?

    1.4 技术关键字

    关键字

    1. Linux Kernel
    2. VFS
    3. Inode / Dentry / Superblock

    一些可以参考的资料

    下期预告

    文件系统篇 Umask 到底影响了谁


    • 水平有限, 有问题欢迎指正.
    • Life is short. We use Python

    一些可以长期关注地方:

    第 1 条附言  ·  2019-09-23 14:38:53 +08:00
    看了大家建议, 似乎叫 "系统知识坑洼之旅其一文件夹也是文件是什么鬼?" 比较合适. 哈哈.
    7 条回复    2019-09-23 15:59:43 +08:00
    ps1aniuge
        1
    ps1aniuge  
       2019-09-23 12:38:40 +08:00
    powershell (.net )没这问题。文件夹,文件,是不同对象。
    Nitroethane
        2
    Nitroethane  
       2019-09-23 12:52:00 +08:00
    “只要明白了它如何组织文件 /文件夹, 基本上就明白了人们常说 everything is a file 的意思”
    你怕是还不明白 everything is a file 的意思,每个打开的 socket 是一个 file,每个设备是一个 file,每个 pipe 也是 file,然而这些跟“它如何组织文件 /文件夹”没有关系
    swulling
        3
    swulling  
       2019-09-23 13:13:21 +08:00
    这个和 Python 踩坑之旅关系不大吧,最近看了一篇 300 行实现文件系统的,可以看看

    https://cloud.tencent.com/developer/article/1497058
    mythmgn
        4
    mythmgn  
    OP
       2019-09-23 14:25:03 +08:00
    @Nitroethane

    文件系统中的 directory 是最容易来理解 everything is a file 的示例.

    (你说的 socket 也好, pipe 也好, 也都是的.
    前几年一直在做分布式文件系统相关项目, 当然理解这些道理. )


    但请仔细看下我想表达的目标, 更多的针对 Directory 啊....
    mythmgn
        5
    mythmgn  
    OP
       2019-09-23 14:25:40 +08:00
    @swulling 是的. 关系不大. 我在文里也提到了. 只是顺带写入这个系列了 哈哈 :)
    mythmgn
        6
    mythmgn  
    OP
       2019-09-23 14:31:57 +08:00
    @Nitroethane 像 pipe 可能还要分 named pipe, anonymous pipe. 存储方式在文件系统上还不一样. 但这不是重点, 写这个更多的针对人群是还不明白为啥文件夹也是文件? 这是为什么? :)
    no1xsyzy
        7
    no1xsyzy  
       2019-09-23 15:59:43 +08:00
    @ps1aniuge .Net 部分符合 POSIX 规范
    FileInfo 和 DirectoryInfo 都是 System.IO.FileSystemInfo
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3356 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 11:25 · PVG 19:25 · LAX 03:25 · JFK 06:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.