Linux系统编程02:文件系统
本文最后更新于343 天前,其中的信息可能已经过时,如有错误请发送邮件到echobydq@gmail.com

前言

此篇文章为学习 Linux系统编程02:文件系统 部分的笔记

1. 文件存储

1.1 inode

inode 是 Linux 和 Unix 操作系统中的一个重要概念,它是文件系统中的一个 数据结构,用于存储文件的元数据。每个文件和目录都有一个对应的 inode 来描述其属性和位置信息。

root@freecho:/opt/C/gcc/code# stat hello.c
  File: hello.c
  Size: 373             Blocks: 8          IO Block: 4096   regular file
Device: b301h/45825d    Inode: 1314593     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-07-26 21:29:11.655510006 +0800
Modify: 2023-07-26 21:29:11.655510006 +0800
Change: 2023-07-26 21:29:11.655510006 +0800
Birth: 2023-07-26 21:29:11.655510006 +0800

inode 结构包含了以下信息:不包含文件名

  1. 文件类型:标识文件是普通文件、目录、符号链接等类型。
  2. 文件权限:文件的读、写、执行权限。
  3. 文件所有者和所属组:标识文件的所有者和所属的用户组。
  4. 文件大小:文件的大小,以字节为单位。
  5. 文件时间戳:记录文件的创建时间、修改时间和访问时间等。
  6. 文件链接数:记录文件的硬链接数目。
  7. 数据块指针:指向文件存储数据的数据块。

当系统中创建一个新文件时,会为该文件分配一个唯一的 inode,然后将文件的实际数据存储在数据块中,并将 inode 中的数据块指针指向这些数据块。在文件被访问或修改时,通过 inode 可以快速定位文件的数据块,而不需要遍历整个文件系统。

通过 ls -i 命令可以查看文件的 inode 号码。每个文件和目录在同一文件系统中具有唯一的 inode 号码。

inode 在文件系统的性能和管理中起着关键作用,它使得文件系统能够高效地管理文件和目录,并支持硬链接的使用。

1.2 dentry

dentry , (即 directory entry 目录项)是 Linux 文件系统中的一个重要概念,用于管理文件系统中的目录。dentryinode 相关联,共同组成了 Linux 文件系统中的目录项。其本质依然是结构体,重要成员变量有两个 {文件名,inode,...},而文件内容(data)保存在磁盘盘块中

每个目录都包含一个或多个 dentry,每个 dentry 表示一个目录中的文件或子目录。dentry 记录了文件或目录的名称、文件类型和对应的 inode 号码等信息。当用户访问文件时,Linux 文件系统会通过 dentry 来快速定位文件的 inode,从而访问文件的实际数据。

在 Linux 文件系统中,dentry 会被缓存在内存中,以提高文件系统的性能。当用户访问文件时,系统首先会查找该文件对应的 dentry 是否已经缓存,如果已经缓存,则直接从 dentry 中获取 inode 信息,避免了不必要的磁盘访问。如果文件对应的 dentry 不在缓存中,系统会通过目录索引进行查找,并将找到的 dentry 缓存起来,以便下次快速访问。

dentry 与目录层次结构一起形成了文件系统的层次结构,通过 dentry 可以在文件系统中快速定位文件和目录,提高了文件系统的访问效率和性能。同时,dentry 的缓存机制也减少了不必要的磁盘访问,提高了整个文件系统的效率。

1.3 文件系统

文件系统是一组规则,规定对文件的存储及读取的一般方法。文件系统在磁盘格式化过程中指定。

以下为常见文件系统:

  1. FAT32(File Allocation Table 32):FAT32是一种较旧的文件系统,广泛应用于可移动介质(如USB闪存驱动器、SD卡等)。它是Windows系统和其他操作系统的通用文件系统。
  2. NTFS(New Technology File System):NTFS是Windows操作系统中使用的主要文件系统。它支持大文件和文件系统,并提供更高级的权限控制和数据安全性。
  3. exFAT(Extended File Allocation Table):exFAT是FAT32文件系统的改进版本,特别设计用于支持更大的文件和分区。它通常在移动存储设备和外部驱动器中使用。
  4. ext2(Second Extended File System):ext2是Linux系统早期的文件系统,不具备日志功能。虽然现在很少使用,但仍然是一些老旧系统的选择。
  5. ext3(Third Extended File System):ext3是ext2文件系统的改进版本,具有日志记录功能,可提供更好的数据完整性和恢复能力。
  6. ext4(Fourth Extended File System):ext4是Linux系统中目前最常用的文件系统,它是ext3文件系统的进一步改进,提供更高的性能和可靠性。ext4支持更大的文件和文件系统,并具备更高级的特性。

1.4 硬链接、软连接

硬链接软链接 (又称软连接)是 Linux 文件系统中两种不同类型的链接方式,用于在文件系统中创建文件或目录之间的关联。

  1. 硬链接(Hard Link):

    • 硬链接是目录项(dentry)中指向相同 inode 号的不同目录项。
    • 通过硬链接,多个文件名可以指向同一个数据块,实际上是同一个文件的不同访问入口。
    • 硬链接创建后,可以像普通文件一样操作,读写内容,删除等,但是不能对目录进行硬链接。
    • 硬链接不能跨文件系统创建,即硬链接必须位于同一个文件系统。
  2. 软链接(Symbolic Link / Soft Link):

    • 软链接是一个特殊的文件,它包含了指向另一个文件或目录的路径名。
    • 软链接类似于 Windows 系统的快捷方式,它只是一个指向目标的快捷方式而已。
    • 软链接可以跨文件系统创建,因为它只保存了目标文件或目录的路径名。
    • 删除软链接并不会影响目标文件或目录,但如果目标文件或目录被删除,软链接将变为"断链"。

对比:

  • 硬链接是多个目录项指向同一个 inode,它们是文件系统中同一个文件的不同名字,文件大小和权限都是相同的。
  • 软链接是一个特殊的文件,它保存了指向目标文件或目录的路径名,它是目标文件或目录的"快捷方式",不占用实际数据块。

注意事项:

  • 删除硬链接或软链接并不会删除目标文件本身。
  • 硬链接不能跨文件系统创建,而软链接可以。

示例:

$ echo "Hello, hard link!" > original.txt
$ ln original.txt hard_link.txt    # 创建硬链接
$ ln -s original.txt soft_link.txt # 创建软链接

$ ls -l
-rw-r--r--  2 user user 18 May 18 2023 hard_link.txt
lrwxrwxrwx  1 user user 13 May 18 2023 soft_link.txt -> original.txt

$ cat hard_link.txt  # 输出:"Hello, hard link!"
$ cat soft_link.txt  # 输出:"Hello, hard link!"

$ rm original.txt   # 删除原始文件
$ cat hard_link.txt  # 输出:"Hello, hard link!",硬链接仍然存在
$ cat soft_link.txt  # 输出:"cat: soft_link.txt: No such file or directory",软链接断链

 

2. 文件操作

2.1 stat、lstat 函数

概念

statlstat函数都用于获取文件或目录的信息,但在处理符号链接时有所不同。

  1. stat函数:

    • 函数原型:int stat(const char *path, struct stat *buf);
    • 描述:stat函数通过指定的文件路径获取文件信息,并将结果存储在struct stat类型的结构体buf中。如果path是一个符号链接,stat函数将会获取符号链接指向的文件的信息。
    • 返回值:成功时返回0,失败时返回-1。
  2. lstat函数:

    • 函数原型:int lstat(const char *path, struct stat *buf);
    • 描述:lstat函数与stat函数类似,也用于获取文件信息。不同之处在于,lstat函数不会跟随符号链接,而是获取符号链接本身的信息,而不是它所指向的文件的信息。
    • 返回值:成功时返回0,失败时返回-1。

这两个函数对于获取文件的权限、大小、时间戳等信息非常有用,而在处理符号链接时,使用lstat函数可以避免不必要的问题。在编写程序时,需要根据具体需求选择使用stat函数还是lstat函数。

buf.st_size  // 获取文件大小
buf.st_mode  // 获取文件类型
buf.st_mode  // 获取文件权限
符号穿透:stat 会  lstat 不会

代码

stat.c :查看文件大小

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

int main(int argc, char *argv[])
{
    struct stat sbuf;

    int ret = stat(argv[1], &sbuf);
    if (ret == -1) {
        perror("stat error");
        exit(1);
    }

    printf("file size: %ld\n", sbuf.st_size);

    return 0;
}

lstat.c : 查看文件属性

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

int main(int argc, char *argv[])
{
    struct stat sbuf;

    int ret = lstat(argv[1], &sbuf);
    if (ret == -1) {
        perror("stat error");
        exit(1);
    }

    if (S_ISREG(sbuf.st_mode)) {
        printf("It's a regular\n");
    } else if (S_ISDIR(sbuf.st_mode)) {
        printf("It's a dir\n");
    } else if (S_ISFIFO(sbuf.st_mode)) {
        printf("It's a pipe\n");
    } else if (S_ISLNK(sbuf.st_mode)) {
        printf("It's a soft link\n");
    }

    return 0;
}

2.2 link、unlink 函数

概念

link函数和unlink函数用于创建硬链接和删除文件链接(硬链接或符号链接)。

  1. link函数: link函数用于创建硬链接。硬链接是指在文件系统中创建一个新的链接指向同一个文件,这个新链接和原文件具有相同的inode号和数据块,但是在目录中显示为一个新的文件名。它的原型为:

    int link(const char *oldpath, const char *newpath);
    

    参数说明:

    • oldpath:源文件路径名,即要创建硬链接的文件。
    • newpath:目标文件路径名,即新创建的硬链接的文件名。

    返回值:

    • 如果成功创建硬链接,返回0。
    • 如果出现错误,返回-1,并设置errno来指示错误类型。
  2. unlink函数: unlink函数用于删除一个文件链接。如果删除的是硬链接,只会删除该链接,而不会删除原文件;如果删除的是符号链接,会删除链接指向的原文件。它的原型为:

    cint unlink(const char *pathname);
    

    参数说明:

    • pathname:要删除的文件路径名,可以是硬链接或符号链接。

    返回值:

    • 如果成功删除文件链接,返回0。
    • 如果出现错误,返回-1,并设置errno来指示错误类型。

这两个函数在Linux系统编程中经常用于文件链接的创建和删除操作。需要注意的是,link函数只能用于同一个文件系统内的文件,而不能跨文件系统创建硬链接。对于跨文件系统的文件链接,可以使用符号链接(符号链接是指在文件系统中创建一个新的文件,它指向另一个文件的路径)来实现。

思考,为什么目录项要游离于 inode 之外,画蛇添足般的将文件名单独存储呢?这样 的存储方式有什么样的好处呢? 其目的是为了实现文件共享。

Linux 允许多个目录项共享一个 inode,即共享盘块(data)。 不同文件名,在人类眼中将它理解成两个文件,但是在内核眼里是同一个文件

link 函数,可以为已经存在的文件创建目录项(硬链接)。unlink 函数则是删除一个文件的目录项

mv 命令即是修改了目录项,而并不修改文件本身。

代码

注意 Linux 下删除文件的机制:不断将 st_nlink -1,直至减到 0 为止。无目录项对应的 文件,将会被操作系统择机释放。(具体时间由系统内部调度算法决定) 因此,我们删除文件,从某种意义上说,只是让文件具备了被释放的条件。

unlink 函数的特征:清除文件时,如果文件的硬链接数到 0 了,没有 dentry 对应,但该 文件仍不会马上被释放。要等到所有打开该文件的进程关闭该文件,系统才会挑时间将该文 件释放掉。

mymv.c :编程实现 mv 命令的改名操作

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    link(argv[1], argv[2]);

    unlink(argv[1]);

    return 0;
}

unlink.c:通过观察临时文件 temp.txt 存在情况,了解unlink函数以及删除文件机制

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
    int fd;
    int ret;
    char *p = "test of unlink\n";
    char *p2 = "after write something.\n";

    fd = open("temp.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); // 临时文件,程序结束销毁
    if (fd < 0) {
        perror("open temp error");
        exit(1);
    }

    ret = unlink("temp.txt"); // // 出现段错误时,temp.txt依然销毁
    if (ret < 0) {
        perror("unlink error");
        exit(1);
    }

    ret = write(fd, p, strlen(p));
    if (ret == -1) {
        perror("--------write error");
    }

    printf("hi! I'm printf\n");
    ret = write(fd, p2, strlen(p2));
    if (ret == -1) {
        perror("--------write error");
    }

    p[3] = 'H';  // 发送段错误

    printf("Enter anykey continue\n");
    getchar();

    close(fd);

    /*
    ret = unlink("temp.txt"); // 出现段错误时,temp.txt无法销毁
    if (ret < 0) {
        perror("unlink error");
        exit(1);
    }
    */

    return 0;
}

2.3 隐式回收

当进程结束运行时,所有该进程打开的文件会被关闭,申请的内存空间会被释放。系统的这一特性称之为隐式回收系统资源。

写程序时一定不能忘记关闭文件

2.4 其他函数

readlink 函数

在Linux中,readlink是一个命令行工具和系统调用,用于读取符号链接(Symbolic Link)所指向的目标路径。

  1. 命令行工具: readlink命令用于查看符号链接的目标路径。使用方法如下:

    readlink [OPTIONS] LINK_PATH
    

    其中,LINK_PATH是符号链接的路径。readlink会输出该符号链接所指向的目标路径。

  2. 系统调用readlink也是一个系统调用,用于在C/C++程序中访问符号链接的目标路径。

    函数原型:

    #include <unistd.h>
    ssize_t readlink(const char *path, char *buf, size_t bufsiz);
    

    参数说明:

    • path:符号链接的路径。
    • buf:用于存储目标路径的缓冲区。
  • bufsiz:缓冲区的大小,应该足够大以容纳目标路径的字符。

返回值:

  • 成功时,返回读取的目标路径的长度(不包括终止空字符),如果目标路径长度大于bufsiz,则返回-1
  • 失败时,返回-1,并设置errno来指示错误类型。

rename 函数

rename函数是一个C标准库函数,用于对文件或目录进行重命名。它在 <stdio.h> 头文件中声明,并且是一个较为简单的文件操作函数。

函数原型:

#include <stdio.h>
int rename(const char *old_path, const char *new_path);

参数说明:

  • old_path:旧的文件名或目录名。
  • new_path:新的文件名或目录名。

返回值:

  • 如果重命名成功,则返回0。
  • 如果重命名失败,则返回-1,并设置errno来指示错误类型。

 

3. 目录操作

3.1 getcwd、chdir 函数

getcwd 函数

获取进程当前工作目录 (卷 3,标库函数)

char *getcwd(char *buf, size_t size); 

成功:buf 中保存当前进程工作目录位置

失败: NULL

chdir 函数

改变当前进程的工作目录

 int chdir(const char *path); 

成功:0

失败:-1 设置 errno 为相应值

3.2 文件、目录权限

注意:目录文件也是“文件”。其文件内容是该目录下所有子文件的目录项 dentry。 可以尝试用 vim 打开一个目录。

 rwx
文件文件的内容可以被查看内容可以被修改可以运行产生一个进程
 cat、more、less…vi、> …./文件名
目录目录可以被浏览创建、删除、修改文件可以被打开、进入
 ls、tree…mv、touch、mkdir…cd

目录设置黏住位:若有 w 权限,创建不变,删除、修改只能由 root、目录所有者、文件所 有者操作。

3.3 目录函数

opendir 函数

返回 :根据传入的目录名打开一个目录 (库函数) DIR * 类似于 FILE *

DIR *opendir(const char *name); 

返回 :成功返回指向该目录结构体指针,失败返回 NULL

参数支持相对路径、绝对路径两种方式

例如:打开当前目录:

  1. getcwd() , opendir()
  2. opendir(".");

closedir 函数

作用:关闭打开的目录

int closedir(DIR *dirp); 

返回 :成功:0; 失败:-1 设置 errno 为相应值

readdir 函数

作用:读取目录 (库函数)

struct dirent *readdir(DIR *dirp); 

返回 :成功返回目录项结构体指针;失败返回NULL设置errno 为相应值

需注意返回值,读取数据结束时也返回 NULL 值,所以应借助 errno 进一步加以区分。

struct 结构体

 struct dirent { 
     ino_t d_ino;            // inode 编号 
     off_t d_off;  
     unsigned short d_reclen; // 文件名有效长度
     unsigned char d_type;   // 类型(vim 打开看到的类似@*/等)
	 char d_name[256];        // 文件名
 };

代码

myls.c:通过以上函数实现 ls 命令

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>

int main(int argc, char *argv[])
{
    DIR *dp;
    struct dirent *sdp;

    dp = opendir(argv[1]);
    if (dp == NULL) {
        perror("open dir error");
        exit(1);
    }

    while ((sdp = readdir(dp)) != NULL) {
        if (strcmp(sdp->d_name, ".") == 0)
            continue;
        if (strcmp(sdp->d_name, "..") == 0)
            continue;
        printf("%s\t", sdp->d_name);
    }

    printf("\n");

    closedir(dp);

    return 0;
}

 

4. 递归遍历目录

查询指定目录,递归列出目录中文件,同时显示文件大小

4.1 思路

  1. 判断命令行参数,获取用户要查询的目录名 argv[1]

    argvc == 1 —> ./

  2. 判断用户指定的是否是目录。不是则打印文件名

    stat S_ISDIR() —> 封装函数 isFile

  3. 读目录:

    opendir()   
    while (readdir()) {
        普通文件:直接打印
        目录:
            拼接目录访问绝对路径   sprintf(path, "%s/%s", dir, d_name)
            递归调用自己
    } 
    closedir()
    

4.2 代码

ls-R.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>

void isFile(char *name);

// 打开目录,读取目录,处理目录
void read_dir(char *dir, void (*func)(char *))
{
    char path[256];
    DIR *dp;
    struct dirent *sdp;

    dp = opendir(dir);
    if (dp == NULL) {
        perror("opendir error");
        return;
    }

    // 读取目录项
    while ((sdp = readdir(dp)) != NULL) {
        if (strcmp(sdp->d_name, ".") == 0 || strcmp(sdp->d_name, "..") == 0) {
            continue;
        }
        // 目录项本身不可访问,拼接 目录/目录项
        sprintf(path, "%s/%s", dir, sdp->d_name);
        // 判断文件类型,目录递归进入,文件显示名字、大小
        //isFile(path);
        func(path);
    }

    closedir(dp);

    return;
}

void isFile(char *name)
{
    int ret = 0;
    struct stat sbuf;

    // 获取文件属性,判断文件类型
    ret = stat(name, &sbuf);
    if (ret == -1) {
        perror("stat error");
        return;
    }

    // 目录文件,进入目录函数
    if (S_ISDIR(sbuf.st_mode)) {
        read_dir(name, isFile);
    }
    // 普通文件,显示文件名、大小
    printf("%10s\t\t%ld\n", name, sbuf.st_size);

    return;
}


int main(int argc, char *argv[])
{
    // 判断命令行参数
    if (argc == 1) {
        isFile(".");
    } else {
        isFile(argv[1]);
    }

    return 0;
}

5. 重定向

dupdup2 是 Linux 系统中用于复制文件描述符的函数,它们都是 C 语言的系统调用函数。它们的作用是创建一个新的文件描述符,该文件描述符是现有文件描述符的副本,指向同一个文件。

5.1 dup 函数

int dup(int oldfd);

dup 函数会复制参数 oldfd 所指向的文件描述符,并返回一个新的文件描述符,该新的文件描述符是系统中当前可用的最小的未使用的文件描述符。

如果复制成功,则返回新的文件描述符;如果复制失败,则返回 -1。

代码

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

int main(int argc, char *argv[])
{
    int fd = open(argv[1], O_RDONLY);
    if (fd == -1) {
        perror("Error opening file");
        return 1;
    }

    // 复制文件描述符
    int new_fd = dup(fd);

    printf("Original file descriptor: %d\n", fd);
    printf("New file descriptor: %d\n", new_fd);

    close(fd); // 注意:关闭原文件描述符不会影响新的文件描述符

    // 使用新的文件描述符读取文件内容
    char buffer[10];
    ssize_t bytes_read = read(new_fd, buffer, sizeof(buffer) - 1);
    buffer[bytes_read] = '\0';
    printf("Content: %s\n", buffer);

    close(new_fd);
    return 0;
}

5.2 dup2 函数

int dup2(int oldfd, int newfd);

dup2 函数与 dup 函数类似,但是它可以指定新的文件描述符的数值。如果 newfd 已经是一个打开的文件描述符,那么 dup2 将首先关闭 newfd,然后将 oldfd 复制到 newfd,确保 newfdoldfd 指向相同的文件。

成功:返回一个新文件描述符; 如果 oldfd 有效,则返回的文件描述符与 oldfd 指向同一文件。

失败:如果 oldfd 无效,调用失败,关闭 newfd。返回-1,同时设置 errno 为相应值

代码

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

int main(int argc, char *argv[])
{
    int fd = open(argv[1], O_RDONLY);
    if (fd == -1) {
        perror("Error opening file");
        return 1;
    }

    // 复制文件描述符到新的文件描述符 100
    int new_fd = dup2(fd, 100);

    printf("Original file descriptor: %d\n", fd);
    printf("New file descriptor: %d\n", new_fd);

    close(fd); // 注意:关闭原文件描述符不会影响新的文件描述符

    // 使用新的文件描述符读取文件内容
    char buffer[100];
    ssize_t bytes_read = read(new_fd, buffer, sizeof(buffer) - 1);
    buffer[bytes_read] = '\0';
    printf("Content: %s\n", buffer);

    close(new_fd);
    return 0;
}

5.3 小结

  • dup 复制文件描述符,返回一个新的文件描述符,值为系统中当前可用的最小未使用的文件描述符。
  • dup2 复制文件描述符到指定的新文件描述符,如果新文件描述符已经打开,则先关闭新文件描述符再复制。
  • 这两个函数在多线程环境下可能会存在竞态条件,使用时需要注意线程安全性。

记忆方法两种:

  1. 文件描述符的本质角度理解记忆。
  2. 从函数原型及使用角度,反向记忆。

练习:借助 dup 函数编写 mycat 程序,实现 cat file1 > file2 命令相似功能

mycat.c

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

int main(int argc, char *argv[])
{
    int fd1, fd2;
    int fdret, ret;

    fd1 = open(argv[1], O_RDWR);
    fd2 = open(argv[2], O_RDWR);

    fdret = dup2(fd1, fd2);  // 返回 新文件描述符fd2
    printf("fdret = %d\n", fdret);

    ret = write(fd2, "1234567", 7); // 写入 fd1 指向的文件
    printf("ret = %d\n", ret);

    dup2(fd1,STDOUT_FILENO); // 将屏幕输入,重定向给 fd1 所指向的文件

    printf("-----------------------886");

    close(fd1);
    close(fd2);

    return 0;
}

5.4 fcntl 实现 dup

当 fcntl 的第二个参数为 F_DUPFD 时, 它的作用是根据一个已有的文件描述符,复制生成一个新的文件描述符。此时,fcntl 相当于 dup 和 dup2 函数。

参 3 指定为 0 时,因为 0 号文件描述符已经被占用。所以函数自动用一个最小可用文件描述符。

参 3 指定为 9 时,如果该文件描述符未被占用,则返回 9。否则,返回大于 9 的可用文件描述符。

fcntl_dup.c

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

int main(int argc, char *argv[])
{
    int fd1 = open(argv[1], O_RDWR);

    printf("fd1 = %d\n", fd1);

    int newfd = fcntl(fd1, F_DUPFD, 0); // 0被占用,fcntl使用文件描述符表中可用的最小文件描述符返回
    printf("newfd = %d\n", newfd);

    int newfd2 = fcntl(fd1, F_DUPFD, 7); // 7,未被占用,返回 >= 7 的文件描述符
    printf("newfd2 = %d\n", newfd2);

    int ret = write(newfd2, "YYYYYYY", 7);
    printf("ret = %d\n", ret);

    close(fd1);

    return 0;
}

 

相关链接

教程视频:Linux系统编程哔哩哔哩bilibili

Linux系列文章:Linux – Echo (liveout.cn)

GCC、GDB、Makefile:GCC、GDB、Makefile学习笔记 – Echo (liveout.cn)

Linux系统编程1:文件I/O笔记:Linux系统编程1:文件I/O

GitHub仓库,包含教程讲义、代码以及笔记:https://github.com/PGwind/LinuxSystem

觉得有帮助可以投喂下博主哦~感谢!
作者:Echo
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0协议
转载请注明文章地址及作者哦~

评论

  1. 冰糖红西柚
    9 月前
    2023-10-27 22:23:55

    哇塞|´・ω・)ノ

    来自吉林
  2. 博客小子
    11 月前
    2023-8-27 10:10:24

    受益匪浅

    来自中国
    • Avatar photo
      博主
      博客小子
      11 月前
      2023-8-29 23:41:59

      来自江苏

发送评论(请正确填写邮箱地址,否则将会当成垃圾评论处理) 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇