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

相关推荐
序属秋秋秋9 小时前
《Linux系统编程之进程环境》【环境变量】
linux·运维·服务器·c语言·c++·操作系统·系统编程
雲烟9 小时前
嵌入式设备EMC安规检测参考
网络·单片机·嵌入式硬件
泽虞9 小时前
《STM32单片机开发》p7
笔记·stm32·单片机·嵌入式硬件
Yue丶越10 小时前
【C语言】数据在内存中的存储
c语言·开发语言·网络
田甲10 小时前
【STM32】 数码管驱动
stm32·单片机·嵌入式硬件
云计算练习生10 小时前
linux shell编程实战 10 Git工具详解与运维场景实战
linux·运维·git
up向上up10 小时前
基于51单片机垃圾箱自动分类加料机快递物流分拣器系统设计
单片机·嵌入式硬件·51单片机
虚伪的空想家12 小时前
KVM的ubuntu虚机如何关闭安全启动
linux·安全·ubuntu
t1987512818 小时前
在Ubuntu 22.04系统上安装libimobiledevice
linux·运维·ubuntu
skywalk816318 小时前
linux安装Code Server 以便Comate IDE和CodeBuddy等都可以远程连上来
linux·运维·服务器·vscode·comate