Linux - 文件操作
记--Linux环境下C语言编程的文件操作。
两种操作文件的方式:
1、系统I/O:系统调用接口,open(), read(), write(), lseek(), close()。是操作系统直接提供的编程接口(API)。 系统I/O常用于硬件级别,可以设置读缓冲区,一般没有写缓冲区;
2. 系统I/O
2.1 open()函数
补充说明:
1)flags 的各种取值可以用位或的方式叠加起来,例如创建文件的时候需要满足这样的 选项:读写方式打开,不存在要新建,如果存在了则清空。则flags 的取值应该是:O_RDWR | O_CREAT | O_TRUNC。
2)mode 是八进制权限,比如0644,或者0755 等。也可以是使用系统已定义的
S_IRWXU 00700 user (file owner) has read, write, and execute permission //用户可读写执行权限
S_IRUSR 00400 user has read permission//用户写权限
S_IWUSR 00200 user has write permission//用户写权限
S_IXUSR 00100 user has execute permission//用户执行权限 (更多选项可查询man手册:man 2 open)
比如新创建的文件权限只需要读写权限:S_IRUSR | S_IWUSR
3)文件描述符
其实是一个数组的下标值,在内核中打开的文件是用 file 结构体来表示的,每一个结构体都会有一个 指针来指向它们,这些指针被统一存放在一个叫做 fd_array 的数组当中,而这个数组被存 放在一个叫做 files_struct 的结构体中,该结构体是进程控制块 task_struct 的重要组成部分。
2.2 close()函数
2.3 read()函数
补充说明:
ssize_t :是类型重定义,为了跨平台兼容。比如说long在32位系统可能是4字节,64位系统可能是8字节,嵌入式开发有的只有16位,那么int只有2个字节。
但是在编程时往往需要根据类型大小来进行操作数据,例如在64位系统编程时8字节使用long类型,如果移植到32位系统时long只有4字节,那么就需要改动好多个地方,所以重定义一种类型,然后根据实际系统再指定,方便改动移植。例如:重定义ssize类型是8字节的,在32位系统,我可以将long long重定义为ssize类型,如果是64位系统可以定义为long类型,这样只需改动一处。
2.4 write()函数
2.5 lseek()函数
示例代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
int fd;
int wr_ret;
int rd_ret;
unsigned long file_size;
char wr_buf[100] = "hello world";
char rd_buf[100];
fd = open("a.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IROTH);//等价于fd = open("a.txt", O_RDWR | O_CREAT | O_TRUNC, 0x604);
if(fd == -1)
{
perror("open file error:");//只有上面的函数设置了error全局错误号,才可使用,会根据error输出对应的错误信息
return -1;
}
printf("fd = %d\n", fd);
wr_ret = write(fd, wr_buf, sizeof(wr_buf));
if(wr_ret == -1)
{
perror("write file error:");
return -1;
}
printf("wr_ret = %d\n", wr_ret);
lseek(fd, 0, SEEK_SET);//上面的写操作,文件位置偏移量也会相应的移动,此处将文件偏移到文件开始位置,然后才能读取刚刚输入的内容
rd_ret = read(fd, rd_buf, sizeof(rd_buf));
if(rd_ret == -1)
{
perror("read file error:");
return -1;
}
printf("rd_ret = %d\n",rd_ret);
printf("content=%s\n", rd_buf);
file_size = lseek(fd, 0, SEEK_END);
printf("file_size = %lu\n", file_size);
close(fd);//关闭文件
return 0;
}
运行结果:
2.6 mmap()函数
更多请查看man手册:man 2 mmap
示例代码:
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h> //mencpy()
int main(void)
{
int fd;
char *map_ptr;
int retval;
fd = open("a.txt",O_RDWR);
if(fd == -1)
{
perror("打开文件失败!");
return -1;
}
map_ptr = mmap( NULL, 100, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(map_ptr == MAP_FAILED)
{
perror("映射内存失败!");
return -1;
}
printf("%s", map_ptr);
memcpy(map_ptr, "haha", 5);
retval = munmap(map_ptr, 100);
if(retval == -1)
{
perror("munmap 失败!");
return -1;
}
close(fd);
return 0;
}
运行结果:
3. 标准I/O
3.1 fopen()函数
程序一开始默认打开3个文件
3.2 fclose()函数
3.3 fread()函数
3.4 fwrite()函数
3.5 fseek()函数
3.6 ftell()函数
3.7 rewind()函数
简单例子:
#include <stdio.h>
int main(int argc,char* argv[])
{
int wr_ret;
int rd_ret;
FILE *fp;
unsigned long file_size;
char wr_buf[100] = "hello world";
char rd_buf[100];
fp = fopen( "a.txt", "a+" );//文件追加,可读可写,文件不存在则创建
if(fp == NULL)
{
perror("open file error:");//只有上面的函数设置了error全局错误号,才可使用,会根据error输出对应的错误信息
return -1;
}
wr_ret = fwrite( wr_buf, sizeof(wr_buf), 1, fp);
printf("wr_ret = %d\n", wr_ret);
rewind(fp);//上面的写操作,文件位置偏移量也会相应的移动,此处将文件偏移到文件开始位置,然后才能读取刚刚输入的内容
rd_ret = fread(rd_buf, sizeof(rd_buf), 1, fp);
printf("rd_ret = %d\n",rd_ret);
printf("content=%s\n", rd_buf);
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
printf("file_size = %lu\n", file_size);
fclose(fp);//关闭文件
return 0;
}
运行结果
————————————————
版权声明:本文为CSDN博主「Genven_Liang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理