代码示例支持
平台: Mac OS
Python: 2.7.10
代码示例:
- wx: 菜单 - Python踩坑指南代码示例
- github 见code_demo

1.1 案例

这期案例讲的是Unix-Like系统中, 常听到的一句话: 目录也是个文件 或者 everything is a file.

刚接触 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

Python 踩坑之旅文件系统篇其一文件夹也是个文件的更多相关文章

  1. Python 踩坑之旅进程篇其三pgid是个什么鬼 (子进程\子孙进程无法kill 退出的解法)

    目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4.1 技术关键字 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: 2.7.14 Github: https: ...

  2. [代码修订版] Python 踩坑之旅 [进程篇其四] 踩透 uid euid suid gid egid sgid的坑坑洼洼

    目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4 技术关键字 1.5 坑后思考 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: 2.7.14 代码示例: 公 ...

  3. Python 踩坑之旅进程篇其四一次性踩透 uid euid suid gid egid sgid的坑坑洼洼

    目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4 技术关键字 1.5 坑后思考 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: 2.7.14 代码示例: 菜 ...

  4. [代码修订版] Python 踩坑之旅进程篇其五打不开的文件

    目录 1.1 踩坑案例 1.2 填坑和分析 1.2.1 从程序优化入手 1.2.2 从资源软硬限入手 1.4.1 技术关键字 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: ...

  5. Python踩坑之旅其一杀不死的Shell子进程

    目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4 坑后扩展 1.4.1 扩展知识 1.4.1 技术关键字 1.5 填坑总结 1.1 踩坑案例 踩坑的程序是个常驻的Agent类管理进程 ...

  6. Python踩坑之旅其二裸用os.system的原罪

    目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4.1 技术关键字 1.5 填坑总结 2. 前坑回顾 2.1 Linux中, 子进程拷贝父进程哪些信息 2.2 Agent常驻进程选择& ...

  7. 美团热修复Robust的踩坑之旅-使用篇

    最近需要在项目中使用热修复框架,在这里以美团的Robust为主写一篇文章总结一下学习的过程. 一直认为要学习一个框架的原理,首先需要让他跑起来,从效果反推回去,这样更容易理解. 一.美团Robust的 ...

  8. vue+ vue-router + webpack 踩坑之旅

    说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案   老司机可以忽略下面的内容了 1)起因  考虑到数据分离的问题  因为server是express搭的   自然少 ...

  9. 微信小程序之mpvue+iview踩坑之旅

    因为之前参照微信的原生的文档写过一些小程序的demo,写的过程比较繁琐,后来出了美团的mpvue,可以直接使用vue开发,其他的不作对比,这篇文章记录一下踩坑之旅. 参照mpvue http://mp ...

随机推荐

  1. Apex 获取真正的IP地址

    代码如下 declare l_ip varchar2(15); begin if OWA_UTIL.GET_CGI_ENV('X-FORWARDED-FOR') is not null then l_ ...

  2. 从SpringBoot构建十万博文聊聊高并发文章浏览量设计

    前言 在经历了,缓存.限流.布隆穿透等等一系列加强功能,十万博客基本算是成型,网站上线以后也加入了百度统计来见证十万+ 的整个过程. 但是百度统计并不能对每篇博文进行详细的浏览量统计,如果做一些热点博 ...

  3. JMeter使用JSON Extractor插件实现将一个接口的JSON返回值作为下一个接口的入参

    ##补充## 接口响应数据,一般为JSON,HTML格式的数据. 对于HTML的响应结果提取,可以使用正则表达式,也可以通过XPath来提取:对于JSON格式的数据,可以用正则表达式,JSON Ext ...

  4. 多线程与高并发(五) Lock

    之前学习了如何使用synchronized关键字来实现同步访问,Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功 ...

  5. rabbitmq生产者的消息确认

    通过Publisher Confirms and Returns机制,生产者可以判断消息是否发送到了exchange及queue,而通过消费者确认机制,Rabbitmq可以决定是否重发消息给消费者,以 ...

  6. 逆向破解之160个CrackMe —— 018

    CrackMe —— 018 160 CrackMe 是比较适合新手学习逆向破解的CrackMe的一个集合一共160个待逆向破解的程序 CrackMe:它们都是一些公开给别人尝试破解的小程序,制作 c ...

  7. 设计模式(C#)——02抽象工厂模式

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321       在工厂模式中,一个工厂只能创建一种产品,但我们往往希望,一个工厂能创建一系列产品.很明显工厂模式已经不能满足我们的需 ...

  8. Delphi - Indy TIdFTP控件实现文件的上传和下载

    FTP信息保存和获取 我们在做FTP相关开发时,为方便后续FTP切换,一般先把FTP账户信息保存到数据库表中,在使用时再通过Query获取出来. 一般通过如下方式获取到FTP相关信息,代码如下: // ...

  9. 【故障公告】阿里云 RDS 数据库服务器 CPU 100% 造成全站故障

    非常非常抱歉,今晚 19:34 ~ 21:16 园子所使用的阿里云 RDS 数据库服务器突然出现 CPU 100% 问题,造成全站无法正常访问,由此您带来了很大的麻烦,请您谅解. 故障经过是这样的.1 ...

  10. 洛谷P1240-诸侯安置+递推非搜索

    诸侯安置 这道题是一题递推题,一开始自己不知道,用了搜索,只过了三个样例: 两两相同的合并, 成 1,1,3,3,5,5........n*2-1; 然后我们会容易发现一种不同与搜索的动态规划做法. ...