网络编程 - FileDescriptor

inode

在描述FileDescriptor之前先来看一下inode。inode在我们后面的描述中会出现,所以首先需要弄清楚它是什么。

inode是index node的简写。它是Unix风格文件系统中的一种数据结构,用来描述比如说文件或目录这样的文件系统对象。每个inode存储对象数据的属性和磁盘块位置。文件系统对象属性可以包括元数据(上次更改的时间、访问、修改)以及所有者和权限数据。

inode中存储的是文件的信息,例如文件所有权、访问模式(读、写、执行权限)和文件类型等。文件的真实数据不存储在inode中,而是存储在称为"数据块"的地方;同时文件的名称也不存储在inode中。在许多类型的文件系统实现中,在创建文件系统时都会固定inode的最大数量,从而限制了文件系统可以容纳的最大文件数。对于文件系统中的inode,典型的分配启发式是总大小的1%。

每个文件都与inode相关联,inode由整数标识,通常称为i-number或inode号。

在设备的已知区域有一张inode表,inode编号就是这个表的索引。根据inode编号,内核的文件系统驱动程序可以访问inode内容,包括文件的位置,从而允许访问文件。

使用ls -i命令可以找到文件的inode号。ls-i命令在报表的第一列中打印 i-node编号。

rockydeMacBook-Pro:~ rocky$ ls -i
14373725 Applications       624053 Movies           14740502 account.txt
624013 Desktop              624055 Music            3800781 default-soapui-workspace.xml
623997 Documents            624057 Pictures         4320031342 node_modules
623999 Downloads            624059 Public           3800780 soapui-settings.xml
624001 Library              670752 Work

如果知道了文件的inode编号,那么可以使用下面的命令来查找文件:

rockydeMacBook-Pro:Work rocky$ ls -i
13583397 config_datasource.properties   13964509 npm-debug.log          13175726 workspace
2913703 document              674806 project
13822742 idea                 670756 software
rockydeMacBook-Pro:Work rocky$ find . -inum 13583397 -print
./config_datasource.properties
rockydeMacBook-Pro:Work rocky$ 

还可以根据文件的inode编号来删除文件:

rockydeMacBook-Pro:Work rocky$ touch 1.txt
rockydeMacBook-Pro:Work rocky$ ls
1.txt               document            npm-debug.log           software
config_datasource.properties    idea                project             workspace
rockydeMacBook-Pro:Work rocky$ ls -li
total 32
4321587203 -rw-r--r--   1 rocky  staff     0 Apr 29 20:41 1.txt
13583397 -rwxrwxrwx@  1 rocky  staff   138 Dec 10  2016 config_datasource.properties
2913703 drwxr-xr-x   8 rocky  staff   256 Nov 21  2016 document
13822742 drwxr-xr-x   4 rocky  staff   128 Mar 21  2017 idea
13964509 -rw-r--r--   1 rocky  staff  8720 Dec  5  2016 npm-debug.log
674806 drwxr-xr-x  20 rocky  staff   640 Apr 28 20:45 project
670756 drwxr-xr-x  23 rocky  staff   736 Apr 24 23:55 software
13175726 drwxr-xr-x   5 rocky  staff   160 Sep  1  2018 workspace
rockydeMacBook-Pro:Work rocky$ find . -inum 4321587203 -delete
rockydeMacBook-Pro:Work rocky$ ls -li
total 32
13583397 -rwxrwxrwx@  1 rocky  staff   138 Dec 10  2016 config_datasource.properties
2913703 drwxr-xr-x   8 rocky  staff   256 Nov 21  2016 document
13822742 drwxr-xr-x   4 rocky  staff   128 Mar 21  2017 idea
13964509 -rw-r--r--   1 rocky  staff  8720 Dec  5  2016 npm-debug.log
674806 drwxr-xr-x  20 rocky  staff   640 Apr 28 20:45 project
670756 drwxr-xr-x  23 rocky  staff   736 Apr 24 23:55 software
13175726 drwxr-xr-x   5 rocky  staff   160 Sep  1  2018 workspace
rockydeMacBook-Pro:Work rocky$ 

一些Unix风格的文件系统(如ReiserFS)省略了inode表,但必须存储等效的数据以提供等效的功能。该数据可以称为stat数据,参考向程序提供数据的stat系统调用。

文件名和目录含义:

  • inode不包含其hardlink名称,只包含其他文件元数据。
  • Unix目录是关联结构的列表,每个结构包含一个文件名和一个inode编号。
  • 文件系统驱动程序必须搜索目录,查找特定的文件名,然后将文件名转换为相应的inode编号。

hardlink

要了解hardlink是什么,重要的是要了解文件的标识是它的inode号,而不是它的名称。hardlink是一个指向inode的名称。这意味着如果file1有一个名为file2的hardlink,那么这两个文件都引用相同的inode。因此,当您为一个文件创建一个hardlink时,您真正要做的就是为一个inode添加一个新的名称。为此,请使用不带选项的ln命令。

# ls -l /home/bobbin/sync.sh  
-rw-r----- 1 root root 5 Apr 7 06:09 /home/bobbin/sync.sh
# ln /home/bobbin/sync.sh synchro

现在让我们比较两个文件:

# ls -il /home/bobbin/sync.sh synchro 
517333 -rw-r----- 2 root root 5 Apr 7 06:09 /home/bobbin/sync.sh
517333 -rw-r----- 2 root root 5 Apr 7 06:09 synchro

关于hard links的有趣之处在于原始文件和link之间没有差异:它们只是连接到同一inode的两个名称。

inode包含的属性

  • File types ( executable, block special etc )
  • Permissions ( read, write etc )
  • UID ( Owner )
  • GID ( Group )
  • FileSize
  • Time stamps including last access, last modification and last inode number change.
  • File deletion time
  • Number of links ( soft/hard )
  • Location of file on harddisk
  • Some other metadata about file.

inode随复制、移动和删除而更改

当复制、移动或删除文件系统上的文件时,inode编号会怎样。

复制文件:CP分配一个空闲的inode编号,并在inode表中放置一个新条目。

### Check inode of existing file 
$ ls -il  myfile.txt
1150561 -rw-r--r-- 1 root root 0 Mar 10 01:06 myfile.txt

### Copy file with new name 
$ cp myfile.txt myfile_new.txt

### Check inode number of new file. Its changed 
$ ls -il myfile_new.txt
1150562 -rw-r--r-- 1 root root 0 Mar 10 01:09 myfile_new.txt

移动或重命名文件:如果目标与源文件系统相同,对inode编号没有影响,它只更改inode表中的时间戳。

### Check inode of existing file 
$ ls -il  myfile.txt
1150561 -rw-r--r-- 1 root root 0 Mar 10 01:06 myfile.txt

### Moved file to another directory 
$ mv myfile.txt /opt/

### Check inode number of moved file. No change in inode 
$ ls -il /opt/myfile.txt
1150561 -rw-r--r-- 1 root root 0 Mar 10 01:06 /opt/myfile.txt

删除一个文件:在Linux中删除一个文件,减少链接计数,释放的inode编号会被重用。

参考:https://tecadmin.net/what-is-inode-number-in-linux/

总结:文件通过文件名进行访问,但事实上,对于文件本身并不与文件名称直接相关联。相反,文件通过inode来访问,inode使用唯一的数值进行标志。该值称为inode编号(inode number),通常简写为i-number或者ino。一个inode存储文件关联的元数据,如它的修改时间戳、所有者、类型、长度以及文件的数据的地址—唯独没有文件名。inode既是Unix文件系统在磁盘上实际物理对象,也是Linux内核中的数据结构的概念实体。

file descriptor

可先阅读: 网络编程 - 文件系统,内核数据结构和打开文件

在Unix和相关的计算机操作系统中,文件描述符(FD)是用于访问文件或其他输入/输出资源(如管道或者网络套接字)的抽象指示符(句柄)。文件描述符构成POSIX应用程序编程接口的一部分。文件描述符是一个非负整数,通常在C编程语言中表示为int类型(保留负值以表示“无值”或错误条件)。

在Unix的传统实现中,文件描述符被索引进由内核维护的进程内文件描述符表(每进程拥有),然后索引为所有进程共享的表示已打开文件的表,称为文件表。此表记录打开文件(或其他资源)的模式:用于读取、写入、附加以及可能的其他模式。它还索引到第三个表,称为inode表,该表描述实际的底层文件。为了执行输入或输出,进程通过系统调用将文件描述符传递给内核,内核将代表进程访问文件。进程无法直接访问文件或inode表

在Linux上,进程中打开的一组文件描述符可以在路径/proc/pid/fd/下访问,其中PID是进程标识符。

在类似Unix的系统中,文件描述符可以引用在文件系统中命名的任何Unix文件类型。除了常规文件之外,它还包括目录、Blockand字符设备(也称为“特殊文件”)、Unix域套接字和命名管道。文件描述符还可以引用文件系统中通常不存在的其他对象,例如匿名管道和网络套接字。

文件描述符-简单
文件描述符-详细

示例-1:

#include <stdio.h>
#include <fcntl.h>

int main()
{
    char c;
    int fd = open("d:\\1.txt", O_RDONLY, 0);
    read(fd, &c, 1);

    printf("c = %c\n", c);
    exit(0);
}

输出:

c = 1

上面程序中fd就是打开文件的文件描述符,read方法执行系统调用将文件描述符作为参数传入进去。由内核执行后续的操作。

示例-2

#include <stdio.h>
#include <fcntl.h>

int main()
{
    int num;
    FILE *fptr;
    fptr = fopen("d:\\1.txt", "w");

    if(fptr == NULL) {
        printf("Error!");
        exit(1);
    }

    fprintf(fptr, "%d", 1213);
    fclose(fptr);

    return 0;
}

示例-2中我们可以看到没有看到文件描述符相关的信息,而是通过FILE类型的指针来进行操作。文件描述符是一个低级别的"句柄",用于标识内核级、Linux和其他类Unix系统中打开的文件(或套接字或其他什么)。C语言对文件描述符进行了包装,提出了文件指针的概念。

文件指针是C标准库级结构,用于表示文件。FILE包装了文件描述符,并添加缓冲和其他功能,以使I/O更容易。

标准文件描述符

在类似Unix的操作系统上,默认情况下,前三个文件描述符是STDIN(标准输入)、STDOUT(标准输出)和STDERR(标准错误)。

名称 数字 描述 缩写
Standard input 0 标准输入流文件描述符。在终端中,默认为来自用户的键盘输入 stdin
Standard output 1 标准输出流描述符。在终端中,默认为用户的屏幕 stdout
Standard error 2 标准错误流描述符。在终端中,默认为用户的屏幕 stderr

FileDescriptor类

上面示例-2中我们可以看到C语言提出了FILE这样的数据结构来包装文件描述符,使得我们能在一个较高的层次上进行文件的操作,而不用直接操作与内核有关的文件描述符。同样Java也进行了包装,提出了FileDescriptor类。

实例-1

@Test
public void test_1() throws IOException {
    FileOutputStream fileOutputStream1 = new FileOutputStream(FileDescriptor.out);
    fileOutputStream1.write(65);
}

运行上面的方法,可以看到屏幕中输出A。

public static final FileDescriptor out = standardStream(1);

FileDescriptor类中定义了上面我们说到的三个标准文件描述符,这里我们使用的就是标准输出文件描述符。持有这个文件描述符那么我们就持有了操作终端屏幕的能力。上面的代码中我们没有使用常用的System.out.println方法来执行向终端屏幕输出字符的功能,而是直接使用标准输出文件描述符来操作,实现相同的效果。

实例-2

@Test
public void test_2() throws IOException {
    File file = new File("D:/1.txt");
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    FileDescriptor fileDescriptor = fileOutputStream.getFD();
    FileOutputStream fileOutputStream1 = new FileOutputStream(fileDescriptor);
    fileOutputStream1.write(65);
}

程序中打开的文件与文件描述符关联。上面的代码中创建了两个FileOutputStream对象,但是它们使用的是一个文件描述符,所以使用第二个FileOutputStream可以实现对1.txt文件的写操作。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容

  • Linux系统一般有4个主要部分:内核、shell、文件系统和应用程序。 内核、shell和文件系统一起形成了基本...
    请爱护小动物阅读 2,564评论 0 22
  • 1. 硬链接和软连接区别 硬连接-------指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区...
    杰伦哎呦哎呦阅读 2,245评论 0 2
  • Linux系统一般有4个主要部分: 内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本...
    偷风筝的人_阅读 3,251评论 1 17
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,739评论 0 10
  • 第一章 1.Linux是一套免费使用和自由传播的类UNIX操作系统,它可以基于Intel x86系列处理器以及Cy...
    yansicing阅读 5,398评论 0 9