一、Linux文件操作概述
在Linux系统编程中,文件操作是核心技能之一。理解文件操作的本质,需要先明确内存与外存的区别:
- 内存(变量、数组、数据结构):
- 读写数据速度快
- 程序执行结束、掉电后数据丢失
- 空间小,价格昂贵
- 文件(外存/硬盘):
- 读写速度比内存慢
- 掉电后数据不丢失
- 空间大,相对内存价格便宜
文件的主要作用有两个:一是长期保存掉电不丢失的数据;二是作为Linux提供给应用层的硬件操作接口,体现了“一切皆文件”的设计哲学。
二、Linux下的文件类型
Linux系统将一切资源都抽象为文件,通过ls -l 文件名命令可以查看文件的详细信息。文件类型由输出行首的第一个字符标识:
- -:普通文件(regular file),如main.c、xxx.txt、a.out
- d:目录文件(directory),如文件夹
- l:软连接文件(link),相当于快捷方式(符号链接)
- b:块设备文件(block),如硬盘等存储设备
- c:字符设备文件(character),如鼠标、键盘、显示器
- s:套接字文件(socket),用于网络编程
- p:管道文件(pipe),用于进程间通信
三、Linux文件操作方法
Linux下的文件操作主要分为两类:
- 标准IO:标准C库提供的文件操作接口,属于库函数
- 文件IO:Linux内核提供的文件操作接口,属于系统调用
无论使用哪种方法,文件操作的基本思想都是相同的:
- 打开文件
- 读文件、写文件
- 关闭文件
四、标准IO操作详解
4.1 打开文件:fopen()
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
功能:打开一个文件,并获得一个文件流指针
参数:
pathname:要打开的文件的文件名mode:打开方式"r":以只读方式打开,文件必须要存在"r+":以读写方式打开,文件必须要存在"w":以只写方式打开,文件不存在则创建,文件存在则清空"w+":以读写方式打开,文件不存在则创建,文件存在则清空"a":以只写方式打开,文件不存在则创建,写时追加写"a+":以读写方式打开,文件不存在则创建,读从开头读,写从末尾写
返回值:
- 成功:FILE*(文件流指针)
- 失败:NULL
4.2 关闭文件:fclose()
int fclose(FILE *stream);
功能:关闭文件
参数:stream:已打开的文件的文件流指针
返回值:
- 成功:0
- 失败:EOF(-1)
注意:只打开文件而使用完不关闭文件,会造成文件描述符泄露。只有 fclose(或 fflush)之后,数据才会从“用户态缓冲区”强制输出到“内核缓冲区”(即操作系统管理的页缓存),从而让其他打开的文件流能够看到它。
4.3 标准流
操作系统默认已打开的三个标准流:
stdin:标准输入流,对应标准输入设备(键盘)stdout:标准输出流,对应标准输出设备(显示屏/终端)stderr:标准出错流,对应标准出错设备(显示屏/终端)
4.4 字符读写:fputc()和fgetc()
int fputc(int c, FILE *stream);
int fgetc(FILE *stream);
fputc()功能:向文件中写入一个字符
fgetc()功能:从文件中读取一个字符
注意:putchar('a')等价于fputc('a', stdout)
4.5 字符串读写:fputs()和fgets()
int fputs(const char *s, FILE *stream);
char *fgets(char *s, int size, FILE *stream);
fputs()功能:将一个字符串写入到文件,不包括'\0'字符
fgets()功能:从文件中读取一行,遇到新行结束
五、实战示例
5.1 使用fgetc读取文件内容
#include <stdio.h>
int main(int argc, const char *argv[])
{
if (argc < 2)
{
printf("Usage : ./a.out <filename>\n");
return -1;
}
FILE *fp = fopen(argv[1], "r");
if (NULL == fp)
{
printf("fopen error\n");
return -1;
}
int ch;
while ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
fclose(fp);
return 0;
}
5.2 实现cp命令功能
#include <stdio.h>
int main(int argc, const char *argv[])
{
if (argc < 3)
{
printf("Usage: ./a.out srcfile dstfile\n");
return -1;
}
FILE *fpsrc = fopen(argv[1], "r");
FILE *fpdst = fopen(argv[2], "w");
if (NULL == fpsrc || NULL == fpdst)
{
printf("fopen error\n");
return -1;
}
int ret = 0;
while (1)
{
ret = fgetc(fpsrc);
if (EOF == ret)
{
break;
}
fputc(ret, fpdst);
}
fclose(fpsrc);
fclose(fpdst);
return 0;
}
六、主函数传参
可以在程序运行时,利用命令行参数向主函数传参:
int main(int argc, const char *argv[])
{
// argc:命令行传递的参数个数
// argv:保存多个char*类型指针的数组
// argv[0] ----> "./mycat"
// argv[1] ----> "1.txt"
// argv[2] ----> "aaa"
// ...
}
示例:执行./mycat 1.txt aaa bbb ccc时:
argc = 4argv[0] = "./mycat"argv[1] = "1.txt"argv[2] = "aaa"argv[3] = "bbb"argv[4] = "ccc"
七、man手册使用
Linux提供了完善的man手册系统,帮助开发者查阅文档:
- Linux命令:
man ls或man 1 ls - 系统调用:
man open或man 2 open - 库函数:
man fopen、man fread、man fclose

1356

被折叠的 条评论
为什么被折叠?



