linux文件管理

目录

原理

[一 c语言接口](#一 c语言接口)

[二 认识文件系统调用](#二 认识文件系统调用)

[三 访问文件的本质](#三 访问文件的本质)


原理

1.文件=内容+属性

2.文件分为打开文件未打开文件

3.打开的文件由进程 打开--本质是研究进程和文件的关系

文件打开后属性一定加载到内存,他与进程1:n

操作系统内部存在在众多打开文件,管理方式为**先描述,再组织,**内核中,打开文件中必须包含自身的文件的打开对象,包含文件属性

4.没打开的文件在磁盘 上,我们需要关注在众多没打开文件中,++文件如何被分门别类的放置好--为进行增删查改快速找到文件。++

一 c语言接口

源码

需要注意"w"是覆盖性写入,而"a"是追加型写入

fopen 是C语言中用于打开文件的标准库函数,功能是创建一个文件指针并关联指定文件,常见用法如下:

基本格式
FILE *fopen(const char *filename, const char *mode);

- filename :要打开的文件名(可含路径)

++路径及CWD,有觉得路径相对路径两种, const char *filename,****我们可以给完整路径(/home/ldg)或者给出文件名(test.c),进程会在他运行得当前路径为我们生成文件。++

- mode :文件打开模式(如 "r" 读、 "w" 写、 "a" 追加等)

常用模式及说明

  • 读操作:

  • "r" :打开文本文件用于读取,文件需存在

  • "rb" :以二进制模式读取

  • 写操作:

  • "w" :创建新文件写入,若文件存在则覆盖

  • "wb" :二进制模式写入

  • "a" :追加内容到文件末尾,文件不存在则创建

  • 读写操作:

  • "r+" :可读可写,文件需存在

  • "w+" :创建新文件,可读可写(覆盖原文件)

返回值

  • 成功时返回指向 FILE 结构体的指针

-失败时返回 NULL (需用 perror 等函数查看错误原因)

注意事项

  • 打开文件后必须用 fclose 关闭,避免资源泄漏

  • 二进制模式需加 b (如 "rb" ),跨平台更安全

  • 处理中文路径时需注意编码问题(Windows下常用GBK)

C常见文件操作接口

cpp 复制代码
//1. 打开与关闭文件
 
-  fopen() :打开文件并返回文件指针
FILE *fp = fopen("file.txt", "r");  // 以只读模式打开文本文件
 
-  fclose() :关闭文件并释放资源
fclose(fp);  // 关闭文件指针fp
 
 
//2. 字符级读写
 
-  fgetc() :从文件读取单个字符
int ch = fgetc(fp);  // 读取一个字符,返回EOF表示读取失败
 
-  fputc() :向文件写入单个字符
fputc('A', fp);  // 向文件写入字符'A'
 
 
//3. 行级读写
 
-  fgets() :读取一行字符串(含换行符)
char buf[100];
fgets(buf, 99, fp);  // 读取最多99个字符到buf
 
-  fputs() :写入字符串(不包含末尾'\0')
fputs("hello", fp);  // 向文件写入"hello"
 
 
//4. 格式化读写
 
-  fscanf() :按格式从文件读取数据
int num;
fscanf(fp, "%d", &num);  // 从文件读取整数
 
-  fprintf() :按格式向文件写入数据
fprintf(fp, "num = %d", 100);  // 写入格式化字符串
 
 
//5. 块读写(二进制文件)
 
-  fread() :读取二进制数据块
struct Data data;
fread(&data, sizeof(data), 1, fp);  // 读取一个结构体
 
-  fwrite() :写入二进制数据块
fwrite(&data, sizeof(data), 1, fp);  // 写入一个结构体
 
 
//6. 文件定位
 
-  fseek() :移动文件指针到指定位置
fseek(fp, 0, SEEK_SET);  // 移动到文件开头(第二个参数:SEEK_SET=开头,SEEK_CUR=当前,SEEK_END=结尾)
 
-  ftell() :获取当前文件指针位置
long pos = ftell(fp);  // 返回当前偏移量(字节数)
 
-  rewind() :重置文件指针到开头
rewind(fp);  // 等价于fseek(fp, 0, SEEK_SET)
 
 
//7. 状态检查
 
-  feof() :检查是否到达文件末尾
if (feof(fp)) printf("已到文件末尾");
 
-  ferror() :检查文件操作是否出错
if (ferror(fp)) perror("文件操作错误");
 
-  clearerr() :清除错误和EOF标志
clearerr(fp);  // 重置错误状态
 
 
//8. 其他工具函数
 
-  remove() :删除文件
remove("old.txt");  // 删除文件old.txt
 
-  rename() :重命名文件
rename("old.txt", "new.txt");  // 重命名文件
 
 
//二进制文件操作需使用 "rb" / "wb" 模式(如 fopen("img.bin", "rb") )。
//- 操作文件前需检查指针是否为 NULL ,避免空指针错误。
//- 频繁读写时可配合 fflush() 刷新缓冲区(如 fflush(fp) 强制写入)。

二 认识文件系统调用

Linux下一位皆是文件

c语言默认启动会打开三个标准输入输出流(文件)

stdin(键盘文件) stdout stderr(显示器文件

我们所说的文件 其实存放在磁盘 ,访问文件其实就是访问磁盘,是外设硬件

用户不能直接访问硬件,需要借助操作系统内部帮助(几乎所以得库只要是访问硬件设备,必须要封装系统调用!!)

介绍接口open

在Linux系统中,open 是用于文件操作的系统调用接口,属于POSIX标准,相比C语言标准库的 fopen 更底层,直接操作文件描述符。以下是其核心用法和解析:

  1. 函数原型与头文件
  • 参数说明:

  • pathname :文件路径(绝对路径或相对路径)。

  • flags :打开文件的标志(必选,可通过**|**组合多个标志)。

  • mode :创建文件时的权限(仅当使用 O_CREAT 标志时有效)。

2. 常用flags标志

基础打开模式(必选其一)

  • O_RDONLY :只读模式(返回文件描述符为可读)。

  • O_WRONLY :只写模式。

  • O_RDWR :读写模式。

扩展标志(可组合使用)

  • O_CREAT :若文件不存在则创建(需配合 mode 参数)。

  • O_APPEND :追加写入(每次写入从文件末尾开始)。

  • O_TRUNC :若文件已存在,清空文件内容。

  • O_EXCL :与 O_CREAT 配合使用时,若文件已存在则打开失败。

  • O_NONBLOCK :非阻塞模式(适用于设备文件,如管道、套接字)。

3. mode参数(文件权限)

当使用 O_CREAT 时,需指定文件权限,通常用八进制表示:

  • 示例: 0666 (所有者、组、其他用户均可读可写)。

  • 实际权限会受当前进程的umask影响(如 umask 002 时,最终权限为 0666 & ~002 = 0664 )。
    可以通过umask接口修改umask值

  1. 返回值与错误处理
  • 成功:返回文件描述符(非负整数,默认最小可用值,如 3 ,标准输入/输出/错误占用 0/1/2 )。

  • 失败:返回 -1 ,可通过 errno 变量或 perror() 查看错误原因(如 ENOENT 文件不存在、 EACCES 权限拒绝)。

  1. 核心操作示例

打开文件并写入

读取文件内容

  1. 与fopen的区别

|----------|-------------------------|-----------------------|
| 特性 | open (系统调用) | fopen (C标准库) |
| 接口层级 | 底层(直接操作文件描述符) | 高层(封装文件流指针) |
| 返回值 | 文件描述符(int类型) | FILE* 指针 |
| 缓冲机制 | 无标准缓冲(需手动管理) | 自带缓冲(提升I/O效率) |
| 跨平台性 | Linux/UNIX专用 跨平台 | (Windows/Linux等) |
| 错误处理 | 通过 errno 或 perror() | 通过返回值和 ferror() 等 |

  1. 其他相关系统调用

- close() :关闭文件描述符

cpp 复制代码
close(fd);  // 成功返回0,失败返回-1

- lseek() :文件指针定位

cpp 复制代码
off_t new_pos = lseek(fd, 0, SEEK_END);  // 移动到文件末尾

- read() / write() :读写数据

cpp 复制代码
ssize_t n = read(fd, buf, size);  // 读取size字节到buf

- fcntl() :文件描述符控制(如设置非阻塞、获取/修改标志)

注意事项

  • 文件描述符是进程级资源,不同进程可通过相同描述符操作文件。

  • 二进制文件无需特殊标志(如 O_BINARY ),Linux系统不区分文本/二进制文件。

  • 多线程环境中需注意文件描述符的线程安全(如共享描述符时加锁)。

三 访问文件的本质

一、文件描述符表的本质与作用

  • 文件描述符(File Descriptor):是进程访问文件的唯一标识符 ,通常为非负整数(如0、1、2等)。

  • 文件描述符表:每个进程都有独立的文件描述符表 ,表中存储了进程当前打开的所有**文件的映射关系,**每个表项对应一个文件描述符,指向内核中的"文件表项"

二、访问磁盘文件的核心流程

  1. 打开文件时的映射建立
  • 进程调用 open() 函数打开磁盘文件时,内核会:

  • 分配一个空闲的文件描述符(通常从最小未使用的整数开始,如3)。

从三开始的原因:stdin,stdout,stderr的占位(进程初始化阶段完成)

  • 创建"文件表项",记录文件的当前偏移量、打开模式(读/写/追加等)、文件状态标志等信息。

  • 文件描述符与文件表项绑定存入进程的文件描述符表。

  1. 通过文件描述符操作文件
  • 进程调用 read() 、 write() 等函数时,只需传入文件描述符:
    **- 内核根据文件描述符查找进程的文件描述符表,定位到对应的文件表项。

  • 通过文件表项找到文件的"索引节点(Inode)"指针,Inode中存储了文件在磁盘上的物理位置、权限、类型等元数据。**

  • 根据Inode信息访问磁盘物理块,完成读写操作。

  1. 关闭文件时的资源释放
  • 进程调用 close() 函数时,内核会:

  • 从文件描述符表中删除对应表项,释放文件描述符。
    - 减少文件表项的引用计数,若计数为0,则释放文件表项及相关资源(如内存缓冲区)

三、关键数据结构与内核层交互

  • 三层数据结构关联:
    进程文件描述符表 → 文件表项 → 索引节点(Inode)→ 磁盘物理块
  • 文件表项:由内核维护,多个进程可通过不同文件描述符指向同一文件表项(如父子进程共享文件)。

  • Inode:每个文件唯一对应一个Inode,存储文件的物理地址映射(如块号数组)。

  • 缓冲区的作用:

内核为文件操作设置缓冲区(如页缓存),读写操作先在内存缓冲区中完成,再由内核异步刷新到磁盘,提升I/O效率。

四、举个简单例子辅助理解

  • 假设进程用 open("/data/file.txt", O_RDONLY) 打开文件:
  1. 内核分配文件描述符 fd=3 ,创建文件表项(记录偏移量0、读模式)。

  2. 进程调用 read(fd, buf, 100) 时,内核通过 fd=3 找到文件表项,根据Inode找到文件在磁盘的位置,从偏移量0读取100字节到 buf 。

  3. 读取后文件表项的偏移量更新为100,下次读取从该位置开始。

五、总结核心逻辑

文件描述符表是进程访问文件的"索引工具",通过它将用户空间的描述符映射到内核空间的文件控制结构,最终实现对磁盘文件的物理访问。这一机制确保了进程对文件的安全管理和高效操作。

相关推荐
morliz子轩5 分钟前
在Docker上部署datalust/Seq日志服务系统
运维·docker·容器
exe4526 分钟前
在docker中部署dify
运维·docker·容器
riverz122727 分钟前
ARM 和 x86_64是什么关系
linux
qq_243050795 小时前
aflplusplus:开源的模糊测试工具!全参数详细教程!Kali Linux教程!(一)
linux·web安全·网络安全·黑客·渗透测试·模糊测试·kali linux
小慧10246 小时前
2.1话题发布
linux·ros
夜影风7 小时前
Linux系统中自签名HTTPS证书
linux·运维·https
wb1897 小时前
流编辑器sed
运维·笔记·ubuntu·云计算
成工小白8 小时前
【Linux】C语言模拟实现shell命令行(程序替换原理)
linux·运维·服务器
西装没钱买9 小时前
C语言多进程TCP服务器与客户端
服务器·c语言·tcp/ip·进程
福理原乡大王9 小时前
Linux信号详解
linux·运维·服务器·c++·ubuntu·信号处理