关于linux操作系统下的文件操作方法:
以下是对笔记中 Linux 文件操作(标准 I/O 为主) 知识点的系统总结,包含核心概念梳理、补充细节,并以表格整理标准 I/O 函数的参数与功能:
一、Linux 应用开发核心方向
笔记围绕 Linux 下的软件开发 展开,核心方向包括:
方向 | 说明 | 关联知识点 |
---|---|---|
文件操作 | 对 Linux 各类文件(块设备、字符设备等)进行读写控制 | 文件类型、标准 I/O/文件 I/O 函数 |
多任务 | 通过进程、线程实现程序并行/并发执行 | 进程创建(fork )、线程管理等 |
网络编程 | 实现网络数据传输、通信 | Socket 编程、TCP/UDP 协议等 |
网络服务器构建 | 开发支持网络请求的服务程序 | HTTP 协议、套接字监听/响应逻辑 |
数据库 | 数据持久化存储与管理 | MySQL、SQLite 等数据库操作 |
二、Linux 文件类型(7 种)
Linux 中“一切皆文件”,通过 ls -l
可查看文件类型(首字符标识 ):
文件类型首字符 | 类型说明 | 典型应用场景 | 示例/备注 |
---|---|---|---|
b | 块设备文件 | 存储设备(硬盘、U盘 ) | /dev/sda (硬盘分区 ) |
c | 字符设备文件 | 输入输出设备(键盘、显示器 ) | /dev/tty (终端 )、/dev/usb |
d | 目录文件 | 存储文件/子目录的“容器” | 任意文件夹(如 /home ) |
- | 普通文件 | 存储文本、二进制、图片等数据 | .c 源码、.txt 文档、可执行文件 |
l | 软链接文件(符号链接 ) | 快捷方式,指向其他文件/目录的路径 | ln -s 原文件 软链接名 创建 |
s | 套接字文件 | 进程间网络通信(本地/网络套接字 ) | /var/run/mysqld/mysqld.sock |
p | 管道文件 | 进程间通信(匿名/命名管道 ) | mkfifo 管道名 创建 |
三、文件操作核心流程
无论标准 I/O 还是文件 I/O,均遵循 “打开 → 读写 → 关闭” 三步:
步骤 | 说明 | 标准 I/O 关键函数 | 文件 I/O 关键函数(补充) |
---|---|---|---|
打开 | 关联文件与程序,获取操作句柄 | fopen (返回 FILE* 流指针 ) | open (返回文件描述符 fd ) |
读写 | 按字符、行、数据块读写内容 | fgetc /fputc 、fgets /fputs | read /write (按字节流读写 ) |
关闭 | 释放资源,确保数据落盘 | fclose | close (关闭文件描述符 ) |
Linux fopen
函数打开模式(mode
)说明表格,包含每种模式的含义、文件存在/不存在时的行为:
模式 | 含义说明 | 文件存在时的行为 | 文件不存在时的行为 | 典型应用场景 |
---|---|---|---|---|
r | 只读(read only) | 打开文件,流指针指向文件开头 | 报错(返回 NULL ) | 读取配置文件、日志文件等 |
r+ | 读写(read + write) | 打开文件,流指针指向文件开头 | 报错(返回 NULL ) | 读取并修改现有文件内容 |
w | 只写(write only,清空文件) | 清空文件内容,流指针指向开头 | 创建新文件 | 覆盖写入全新内容(如日志重置) |
w+ | 读写(write + read,清空文件) | 清空文件内容,流指针指向开头 | 创建新文件 | 覆盖写入并需要读取的场景 |
a | 追加写(append only) | 流指针移到文件末尾(保留内容) | 创建新文件 | 日志追加、消息队列写入 |
a+ | 追加读写(append + read) | 读:指针在开头;写:指针在末尾 | 创建新文件 | 追加内容同时需要回读的场景 |
补充说明
-
模式区分细节:
r
/r+
严格依赖文件已存在,否则直接失败(返回NULL
,需检查errno
确认错误 )。w
/w+
会强制清空现有文件(即使文件有内容 ),适合“覆盖写入”场景。a
/a+
的写操作始终在文件末尾(无论指针如何移动 ),但读操作可自由调整指针位置(如fseek
)。
-
实践建议:
- 打开文件后务必检查返回值(
if (fp == NULL) { perror("fopen"); exit(1); }
)。 - 不同模式的指针行为需注意,尤其是
a+
模式(读和写的指针位置独立 )。
- 打开文件后务必检查返回值(
-
跨平台差异:
Windows 系统下,fopen
模式需额外区分文本模式("rt"
/"wt"
)和二进制模式("rb"
/"wb"
),但 Linux 下无此严格区分(默认二进制模式 )。
通过表格可直观对比各模式的行为差异,开发时根据需求(读、写、追加、覆盖 )选择对应模式即可。
四、标准 I/O 函数总结(核心函数参数 & 功能表)
标准 I/O 由 C 标准库(stdio.h
)提供,基于 文件流(FILE*
) 操作,核心函数如下:
1. 文件打开:fopen
FILE *fopen(const char *pathname, const char *mode);
要素 | 说明 |
---|---|
功能 | 打开文件并返回 文件流指针(FILE* ),失败返回 NULL 。 |
参数 | - pathname :文件路径(如 "/tmp/test.txt" )- mode :打开模式(见下表) |
返回值 | 成功返回 FILE* 流指针,失败返回 NULL (需检查 errno 定位错误)。 |
需要检查返回值以判断文件是否成功打开:
FILE *fp=fopen("./1.txt","w+");FILE *fp1=fp;if(fp==NULL){printf("fopen error\n");return -1;}
2. 文件关闭:fclose
int fclose(FILE *stream);
要素 | 说明 |
---|---|
功能 | 关闭文件流,刷新缓冲区,释放资源。 |
参数 | stream :fopen 返回的文件流指针(FILE* )。 |
返回值 | 成功返回 0 ,失败返回 EOF (需检查 ferror(stream) 确认错误)。 |
对文件执行fopen后别忘了执行fclose关闭打开的文件:
3. 字符读写:fgetc
/ fputc
- 读字符:
fgetc
int fgetc(FILE *stream);
要素 | 说明 |
---|---|
功能 | 从文件流 stream 读取一个字符(ASCII 码),流指针后移 1 字节。 |
参数 | stream :文件流指针(FILE* )。 |
返回值 | 成功返回字符的 ASCII 码(int 类型,如 'A' 对应 65 );失败/到文件末尾返回 EOF 。 |
代码:
#include<stdio.h>
int main(void)
{FILE *fp=fopen("./1.txt","w+");FILE *fp1=fp;if(fp==NULL){printf("fopen error\n");return -1;}fputc('h',fp);fputc('e',fp);fputc('l',fp);fputc('l',fp);fputc('o',fp);fputc(' ',fp);fputc('w',fp);fputc('o',fp);fputc('r',fp);fputc('l',fp);fputc('d',fp);int ret=fgetc(fp1);
/* if(ret==EOF){printf("end of file or error\n");}*/while(ret!=EOF){printf("%c",ret);ret=fgetc(fp1);}fclose(fp);printf("fopen successful\n");return 0;
}
- 写字符:
fputc
int fputc(int c, FILE *stream);
要素 | 说明 |
---|---|
功能 | 向文件流 stream 写入一个字符(c 的 ASCII 码),流指针后移 1 字节。 |
参数 | - c :要写入的字符(如 'A' 或直接传 ASCII 码 65 )- stream :文件流指针 |
返回值 | 成功返回写入字符的 ASCII 码;失败返回 EOF 。 |
代码:逐个字符读取:
#include<stdio.h>
int main(void)
{FILE *fp=fopen("1.txt","r");int ret=fgetc(fp);
/* if(ret==EOF){printf("end of file or error\n");}*/while(ret!=EOF){printf("%c",ret);ret=fgetc(fp);}fclose(fp);printf("fopen successful\n");return 0;
}
4. 行读写:fgets
/ fputs
- 读一行:
fgets
char *fgets(char *s, int size, FILE *stream);
要素 | 说明 |
---|---|
功能 | 从文件流 stream 读取一行数据(最多读 size-1 个字符,遇 \n 或文件末尾停止 ),自动在 s 末尾加 \0 。 |
参数 | - s :存储数据的缓冲区(字符数组,如 char buf[1024] )- size :缓冲区大小(需 >1,预留 \0 空间 )- stream :文件流指针 |
返回值 | 成功返回 s 缓冲区地址;失败/到文件末尾返回 NULL 。 |
代码:
#include<stdio.h>
int main(int argc, const char *argv[])
{FILE *PGS=fopen("./4.txt","r");if(PGS==NULL){printf("fopen error\n");return -1;}char s[100]={0};char *p=fgets(s,sizeof(s),PGS);if(p==NULL){printf("fgets error or fgets the end of file\n");return -1;}printf("%s\n",p);fclose(PGS);return 0;
}
- 写一行:
fputs
int fputs(const char *s, FILE *stream);
要素 | 说明 |
---|---|
功能 | 向文件流 stream 写入字符串(s 内容,不自动加 \n ,需手动添加 )。 |
参数 | - s :要写入的字符串(以 \0 结尾,如 "hello" )- stream :文件流指针 |
返回值 | 成功返回非负整数(通常是写入字符数 );失败返回 EOF 。 |
代码:
#include<stdio.h>
int main(int argc , const char *argv[])
{FILE *FP=fopen("./4.txt","w");if(FP==NULL){printf("fopen error\n");return -1;}char s[100]={"china!\n"};int ret=fputs(s,FP);if(ret==EOF){printf("fputs error!\n");return -1;}return 0;
}
5. 数据块读写:fread
/ fwrite
(补充)
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
要素 | 说明 |
---|---|
功能 | 按数据块读写文件(适合二进制文件,如结构体、图片 )。 |
参数 | - ptr :缓冲区地址(读时存数据,写时取数据 )- size :单个数据块大小(字节 )- nmemb :数据块数量- stream :文件流指针 |
返回值 | 实际读写的数据块数量(size_t );失败或到末尾可能小于 nmemb 。 |
五、补充细节 & 易错点
-
文件流指针移动:
读写操作会改变流指针位置(如fgetc
后指针后移 1 字符 ),同一程序中“写后直接读”需用fseek
重置指针(如fseek(stream, 0, SEEK_SET)
回到文件开头 )。 -
缓冲区机制:
标准 I/O 带用户态缓冲区,数据先写入缓冲区,再由系统决定何时刷入磁盘。需立即落盘时,调用fflush(stream)
手动刷新。 -
命令行参数:
argc
/argv
主函数参数用于接收命令行输入:int main(int argc, char *argv[]);
argc
:参数总个数(含程序名 )。argv
:参数数组,argv[0]
是程序路径/名称,argv[1]
开始是用户输入参数。
六,主函数传参的使用方法
以下是结合笔记内容,对 Linux C 主函数传参(argc
/argv
) 的总结与补充,用清晰的逻辑和示例说明用法:
1、主函数传参基础概念
在 Linux C 程序中,主函数 main
支持通过命令行传递参数,形式为:
int main(int argc, char *argv[]);
参数名 | 含义 |
---|---|
argc | 参数个数(argument count):包含程序名在内的所有命令行参数总数。 |
argv | 参数数组(argument vector):字符串数组,存储每个命令行参数的内容。 |
2、传参规则与示例
以笔记中示例 ./a.out aaa bbb
为例:
命令行输入 | argc 值 | argv 数组内容 | 说明 |
---|---|---|---|
./a.out aaa bbb | 3 | argv[0] = "./a.out" argv[1] = "aaa" argv[2] = "bbb" | - argv[0] 固定为程序名/路径 - argv[1] 开始是用户传入的参数 |
3、传参方法与场景
1. 基础用法:命令行直接传参
编译生成可执行文件(如 a.out
)后,在终端通过以下方式传参:
./a.out 参数1 参数2 参数3 ...
- 示例代码(遍历参数):
#include <stdio.h> int main(int argc, char *argv[]) { printf("参数总数 argc = %d\n", argc); for (int i = 0; i < argc; i++) { printf("argv[%d] = %s\n", i, argv[i]); } return 0; }
- 运行输出(输入
./a.out aaa bbb
):参数总数 argc = 3 argv[0] = ./a.out argv[1] = aaa argv[2] = bbb
4、关键细节补充
-
argv
数组的结束标志:
argv[argc]
固定为NULL
,可用于遍历参数时的终止判断:for (int i = 0; argv[i] != NULL; i++) { printf("argv[%d] = %s\n", i, argv[i]); }
-
参数的本质是字符串:
argv
存储的是字符串,如需数值运算(如./app 10 20
),需用atoi
/atof
转换:#include <stdlib.h> int num1 = atoi(argv[1]); // "10" → 10 int num2 = atoi(argv[2]); // "20" → 20
-
空格与引号处理:
- 命令行参数以空格分隔,如需传递含空格的参数,用引号包裹:
./app "hello world" # argv[1] = "hello world"(含空格)
- 特殊字符(如
$
、*
)需用反斜杠转义(\
)或引号包裹。
- 命令行参数以空格分隔,如需传递含空格的参数,用引号包裹:
七、总结表格(标准 I/O 核心函数参数速查表)
函数 | 函数原型 | 核心参数说明 | 典型用途 |
---|---|---|---|
fopen | FILE *fopen(const char *pathname, const char *mode); | pathname (路径)、mode (打开模式) | 打开文件并获取流指针 |
fclose | int fclose(FILE *stream); | stream (文件流指针) | 关闭文件、刷新缓冲区 |
fgetc | int fgetc(FILE *stream); | stream (文件流指针) | 读 1 个字符 |
fputc | int fputc(int c, FILE *stream); | c (字符)、stream (文件流指针) | 写 1 个字符 |
fgets | char *fgets(char *s, int size, FILE *stream); | s (缓冲区)、size (最大读入字符 )、stream (文件流指针) | 读 1 行数据 |
fputs | int fputs(const char *s, FILE *stream); | s (字符串)、stream (文件流指针) | 写 1 行字符串(不含 \0 ) |
使用fopen ,fputc,fgetc,fclose实现拷贝的功能:
代码:
#include<stdio.h>
int main(int argc ,const char *argv[])
{if(argc!=3){printf("Usage : ./a.out <srcfile> <dstfile>\n");return -1;}FILE *fp=fopen(argv[1],"r");if(fp==NULL){printf("fopen error\n");return -1;}FILE *fcp=fopen(argv[2],"w");if(fcp==NULL){printf("fopen error\n");return -1;}int ret =fgetc(fp);if(ret==EOF) {printf("end of file or error");}while(ret!=EOF){fputc(ret,fcp);ret=fgetc(fp);}fclose(fp);fclose(fcp);return 0;
}
使用fopen,fgets,fputs,fclose库函数实现字符串的拷贝:
代码
#include<stdio.h>
int main(int argc,const char *argv[])
{if(argc!=3){printf("Usage : copy <srcfile> <dstfile>\n");return -1;}FILE *FGT=fopen(argv[1],"r");if(FGT==NULL){printf("fopen error\n");return -1;}FILE *FPT=fopen(argv[2],"w");if(FPT==NULL){printf("fopen error\n");return -1;}char s[100]={0};char *fgt=fgets(s,sizeof(s),FGT);if(fgt==NULL){printf("fgets error or fgets the end of the file");return -1;}int fpt=fputs(fgt,FPT);if(fpt==EOF){printf("fputs error\n");return -1;}fclose(FGT);fclose(FPT);return 0;
}