Linux C编程:文件IO(概念、打开、读、写、关闭)

wx:嵌入式工程师成长日记

https://mp.weixin.qq.com/s/NbYVE8hsU7V_48nbNsUByA?token=382885458&lang=zh_CNhttps://mp.weixin.qq.com/s/NbYVE8hsU7V_48nbNsUByA?token=382885458&lang=zh_CN

操作文件有专属的系统函数,系统函数并不是内核函数,因为内核函数是不允许用户使用的,系统函数就充当了二者之间的桥梁,这样用户就可以间接的完成某些内核操作了。

在Linux系统中必须要使用系统提供的IO函数才能基于这些文件描述符完成对相关文件的读写操作。

1.open()

open()是一个系统函数,只能在linux系统中使用, windows不支持。

fopen() 是标准c库函数, 一般可以跨平台使用。

// 打开一个已经存在的磁盘文件int open(const char *pathname, int flags);// 打开磁盘文件, 如果文件不存在, 就会自动创建int open(const char *pathname, int flags, mode_t mode);

参数:

1.pathname: 被打开的文件的路径文件名

2.flags:使用什么方式打开指定的文件,必须要指定的属性, 以下三个属性不能同时使用, 只能任选其一:

O_RDONLY: 以只读方式打开文件

O_WRONLY: 以只写方式打开文件

O_RDWR: 以读写方式打开文件

(可选属性):

O_APPEND: 新数据追加到文件尾部, 不会覆盖文件的原来内容

O_CREAT: 如果文件不存在, 创建该文件, 如果文件存在什么也不做

O_EXCL: 检测文件是否存在, 必须要和O_CREAT 一起使用, 不能单独使用: O_CREAT | O_EXCL;(若检测到文件不存在, 则创建新文件,检测到文件已经存在,创建失败,函数直接返回-1)

3.mode: 在创建新文件的时候才需要指定这个参数的值,用于指定新文件的权限,这是一个八进制的整数。(该最大值为:0777)

创建的新文件对应的最终实际权限, 计算公式: (mode & ~umask)

umask 掩码可以通过 umask 命令查看

4.返回值:

成功: 返回内核分配的文件描述符,是一个大于0的整数

失败: -1

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>
int main(){    // 打开文件    int fd = open("abc.txt", O_RDWR);    if(fd == -1)    {        printf("打开文件失败\n");    }    else    {        printf("fd: %d\n", fd);    }
    close(fd);    return 0;}

2.close()

功能:关闭文件并释放文件描述符

#include <unistd.h>int close(int fd);

3.read()

功能:用于读取文件内部数据

#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);

参数:

fd: 文件描述符, open() 函数的返回值,通过这个参数定位打开的磁盘文件

buf: 传出参数, 指向一块有效的内存, 用于存储从文件中读出的数据

count: buf指针指向的内存的大小, 指定可以存储的最大字节数

返回值:

大于0: 从文件中读出的字节数,读文件成功

等于0: 代表文件读完了,读文件成功

-1: 读文件失败

4.write()

功能:用于将数据写入到文件内部

#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);

参数:

fd: 文件描述符, open() 函数的返回值, 通过这个参数定位打开的磁盘文件

buf: 指向一块有效的内存地址, 里边有要写入到磁盘文件中的数据

count: 要往磁盘文件中写入的字节数, 一般情况下就是buf字符串的长度, 调用strlen(buf)即可求得

返回值:

大于0: 成功写入到磁盘文件中的字节数

-1: 写文件失败了

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>
int main(){    // 打开存在的文件a.txt, 读这个文件    int fd1 = open("./a.txt", O_RDONLY);    if(fd1 == -1)    {        perror("error");        return -1;    }
    // 打开不存在的文件, 将其创建出来, 将从a.txt读出的内容写入这个文件中    int fd2 = open("b.txt", O_WRONLY|O_CREAT, 0664);    if(fd2 == -1)    {        perror("error");        return -1;    }
    // 循环读文件, 循环写文件    char buf[4096];    int len = -1;    while( (len = read(fd1, buf, sizeof(buf))) > 0 )    {     // 将读到的数据写入到另一个文件中        write(fd2, buf, len);     }    // 关闭文件    close(fd1);    close(fd2);
    return 0;}

5.lseek()

功能:通过这个函数移动文件指针, 也可以通过这个函数进行文件的拓展

#include <sys/types.h>#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

参数:

fd: 文件描述符, open() 函数的返回值, 通过这个参数定位打开的磁盘文件

offset: 偏移量,需配合第三个参数使用

whence: 以下三个参数任选其中一个

SEEK_SET: 从文件头部开始偏移 offset 个字节

SEEK_CUR: 从当前文件指针的位置向后偏移offset个字节

SEEK_END: 从文件尾部向后偏移offset个字节

返回值:

成功: 文件指针从头部开始计算总的偏移量

失败: -1

三种用法:

//文件指针移动到文件头部lseek(fd, 0, SEEK_SET);//得到当前文件指针的位置lseek(fd, 0, SEEK_CUR); //得到文件总大小lseek(fd, 0, SEEK_END);

利用lseek()实现文件扩展

注意:

使用 lseek 函数进行文件拓展必须要满足以下条件:

1.文件指针必须要偏移到文件尾部之后,多出来的就需要被填充的部分

2.文件拓展之后,必须要使用write()函数进行一次写操作(写什么都可以)

#include <stdio.h>#include <fcntl.h>#include <unistd.h>int main(){    int fd = open("a.txt", O_RDWR);    if(fd == -1)    {        perror("error");        return -1;    }
    // 文件一共拓展了 1001 个字节    lseek(fd, 1000, SEEK_END);    write(fd, " ", 1);
    close(fd);    return 0;}

6.truncate()/ftruncate()

功能:修改指定文件大小,用来拓展文件,比lseek()使用更简单

#include <unistd.h>#include <sys/types.h>
int truncate(const char *path, off_t length);-int ftruncate(int fd, off_t length);

参数:

path: 要拓展/截断的文件的文件名

fd: 文件描述符

length: 有以下两种情况:

①文件原来size > length,文件被截断, 尾部多余的部分被删除, 文件最终长度为length

②文件原来size < length,文件被拓展, 文件最终长度为length

返回值:

成功则返回0

失败则返回-1

相关推荐
王军新18 分钟前
Ubuntu把应用程序放到桌面
linux
monstercl24 分钟前
【服务器】Ubuntu22.04配置静态ip
linux·运维·服务器·tcp/ip·ubuntu
云山工作室24 分钟前
基于单片机的直流电机控制系统(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
JoYER_cc1 小时前
C 陷阱与缺陷 —— Chapter one 词法陷阱
c语言·开发语言
怎么昵称都被占用啊2 小时前
【Linux系统环境中使用二进制包安装Apache】
linux·运维·apache
艾格北峰2 小时前
STM32 物联网智能家居 (五) 设备子系统之点亮LED灯
arm开发·stm32·单片机·嵌入式硬件·物联网·架构·智能家居
我们的五年3 小时前
【C++课程学习】:C++中的IO流(istream,iostream,fstream,sstream)
linux·c++·学习
工程师焱记3 小时前
Linux 常用命令——文件目录篇(保姆级说明)
linux
Ronin-Lotus3 小时前
嵌入式硬件篇---基本组合逻辑电路
stm32·单片机·嵌入式硬件·学习·信息可视化
Ronin-Lotus3 小时前
嵌入式硬件篇---PID控制
单片机·嵌入式硬件·mcu·学习·程序人生·算法·硬件工程