Linux 文件与目录操作详解
目录
简介
基本概念
1. 常见文件类型操作接口:
系统库(简单跨平台)
C 标准库(高性能底层调用)
2. 文件与目录操作核心函数
标准库 FILE*
系统调用
目录操作
项目实战一:实现 wc 功能
功能示例
关键点
代码实现
项目实战二:文件分卷与哈希摘要
示例
使用接口
openssl 安装
代码实现
总结
简介
在 Linux 系统中,一切皆文件。本文从 Linux 文件的基本操作函数讲起,结合三个实际任务案例,带你全面掌握文件读写、目录遍历、文件切片、哈希摘要等常用操作。无论你是系统程序员、服务器开发者,还是操作系统课程的学习者,本篇内容都能帮你打好底层基础。
基本概念
Linux 把所有内容抽象为文件,统一进行读写操作:
-
普通文件与文件夹
-
设备文件(如
/dev/null
) -
网络套接字
-
进程信息(如
/proc/self
)
文件的抽象来源于“流”的概念 —— 一串从源头流向目的地的字节序列。
1. 常见文件类型操作接口:
系统库(简单跨平台)
- `open`
- `close`
- `read`
- `write`
- `ioctrl`
C 标准库(高性能底层调用)
- `fopen`
- `fclose`
- `fread`
- `fwrite`
- `fseek`
- `fgetc`
- `fputc`
- `fgets`
- `fputs`
2. 文件与目录操作核心函数
标准库 FILE*
适用于文本文件和缓冲处理:
FILE *fp = fopen("a.txt", "r"); // 打开一个用于读取的文件。该文件必须存在。
fgetc(fp); // 读取单个字符
fgets(buf, n, fp); // 读取一行
fclose(fp); // 关闭文件
mode
- r 只读
- r+ 读写
- w 只写,截断
- w+ 读写,截断
- a 追加
- a+ 追加读
- b 二进制格式
系统调用
适合大文件和高并发场景:
int fd = open("a.txt", O_RDONLY);
read(fd, buf, n);
lseek(fd, offset, SEEK_SET);
close(fd);
目录操作
需引入头文件 <dirent.h>
和 <sys/stat.h>
:
DIR *dp = opendir(".");
struct dirent *entry;
while ((entry = readdir(dp)) != NULL) {printf("%s\n", entry->d_name);
}
closedir(dp);
项目实战一:实现 wc
功能
目标:实现命令 wc
的常用功能(字节数、词数、行数)
功能示例
./wc -c a.txt # 字节数
./wc -w a.txt # 单词数
./wc -l a.txt # 行数
./wc a.txt # 全部统计
关键点
-
fgetc()
逐字符读取 -
判断空格、换行、制表符统计词数
-
行数遇
'\n'
增加 -
使用
fseek + ftell
获取文件大小(字节数)
代码实现
// 简单实现 wc 的功能
#include <stdio.h>
#include <stdlib.h>
#include <string.h>void count_file(const char *filename, int count_line, int count_word, int count_byte);int main(int argc, char const *argv[])
{if (argc < 2){printf("用法: %s [-c] [-w] [-l] 文件名\n", argv[0]);return EXIT_FAILURE;}int count_line = 0;int count_word = 0;int count_byte = 0;const char *filename = NULL;for (int i = 1; i < argc; i++){if (strcmp(argv[i], "-l") == 0){count_line = 1;}else if (strcmp(argv[i], "-w") == 0){count_word = 1;}else if (strcmp(argv[i], "-c") == 0){count_byte = 1;}else{filename = argv[i];}}if (!filename){fprintf(stderr, "未指定文件名\n");return EXIT_FAILURE;}count_file(filename, count_line, count_word, count_byte);return EXIT_SUCCESS;
}void count_file(const char *filename, int count_line, int count_word, int count_byte)
{FILE *fp = fopen(filename, "r");if (!fp){perror("文件打开失败");return;}int lines = 0;int words = 0;int bytes = 0;int in_word = 0;int c;while ((c = fgetc(fp)) != EOF){bytes++;if (c == '\n') lines++;if (c == ' ' || c == '\n' || c == '\t'){in_word = 0;}else if (!in_word){in_word = 1;words++;}}fclose(fp);if (!count_line && !count_word && !count_byte){count_line = count_word = count_byte = 1;}if (count_line) printf("行数: %d\n", lines);if (count_word) printf("单词数: %d\n", words);if (count_byte) printf("字节数: %d\n", bytes);
}
项目实战二:文件分卷与哈希摘要
目标:将大文件按固定大小切分,并对每一部分计算 SHA256 哈希
示例
./split a.txt 512
# 输出文件:
# a.txt.001
# a.txt.002
# ...
# m.txt # 各分卷哈希值 + 全文件哈希
使用接口
-
open
,read
,write
实现二进制读取与写入 -
openssl/sha.h
+SHA256()
计算哈希 -
文件命名使用
snprintf
构造a.txt.001
openssl 安装
sudo apt install libssl-dev
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <openssl/sha.h>
#include <sys/stat.h>void sha256_hash(const unsigned char *data, size_t len, char *out_hex) {unsigned char hash[SHA256_DIGEST_LENGTH];SHA256(data, len, hash);for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {sprintf(out_hex + i * 2, "%02x", hash[i]);}
}int main(int argc, char *argv[]) {if (argc != 3) {printf("用法: %s 文件名 分卷大小(字节)\n", argv[0]);return 1;}const char *filename = argv[1];int chunk_size = atoi(argv[2]);int fd = open(filename, O_RDONLY);if (fd < 0) {perror("open");return 1;}unsigned char *buffer = malloc(chunk_size);if (!buffer) {perror("malloc");close(fd);return 1;}FILE *meta_fp = fopen("m.txt", "w");if (!meta_fp) {perror("fopen m.txt");free(buffer);close(fd);return 1;}int chunk_num = 1;ssize_t read_bytes;SHA256_CTX full_ctx;SHA256_Init(&full_ctx);while ((read_bytes = read(fd, buffer, chunk_size)) > 0) {char sha_hex[65] = {0};sha256_hash(buffer, read_bytes, sha_hex);// 写入分卷char part_filename[256];snprintf(part_filename, sizeof(part_filename), "%s.%03d", filename, chunk_num++);FILE *part_fp = fopen(part_filename, "wb");fwrite(buffer, 1, read_bytes, part_fp);fclose(part_fp);fprintf(meta_fp, "%s\n", sha_hex);SHA256_Update(&full_ctx, buffer, read_bytes);}// 计算整个文件的 SHA256unsigned char full_hash[SHA256_DIGEST_LENGTH];SHA256_Final(full_hash, &full_ctx);char final_sha[65] = {0};for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {sprintf(final_sha + i * 2, "%02x", full_hash[i]);}fprintf(meta_fp, "%s\n", final_sha); // 写入最后一行printf("完整文件 SHA256: %s\n", final_sha);fclose(meta_fp);close(fd);free(buffer);return 0;
}
总结
本文从文件操作的基本概念出发,结合 wc
命令实现与文件分卷哈希两个实战案例,全面介绍了 Linux 下文件与目录的读写方法及系统调用的实际应用。通过这些练习,读者不仅能掌握文本与二进制文件的处理技巧,还能理解哈希摘要在数据完整性校验中的重要作用,为后续深入系统编程与工具开发打下坚实基础。