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

相关推荐
长臂人猿1 分钟前
JVM常用工具:jstat、jmap、jstack
linux·运维·jvm
轻松Ai享生活29 分钟前
揭秘 linux:一张图看懂系统配置的核心
linux
wdxylb38 分钟前
云原生俱乐部-RH134知识点总结(2)
linux·云原生
_Chipen1 小时前
lazy_vim_cmake_clangd_从零到自动补全与语法检查
linux·编辑器·vim
逼子格2 小时前
AT89C52单片机介绍
单片机·嵌入式硬件·51单片机·硬件工程师·硬件工程师真题·at89c52·器件手册
椰子今天很可爱2 小时前
静态库和动态库
linux
檀越剑指大厂2 小时前
【Linux系列】如何在 Linux 服务器上快速获取公网
linux·服务器·php
共享家95272 小时前
linux-高级IO(上)
java·linux·服务器
丑小鸭是白天鹅3 小时前
嵌入式C语言学习笔记之枚举、联合体
c语言·笔记·学习
GUET_一路向前4 小时前
【C语言防御性编程】if条件常量在前,变量在后
c语言·开发语言·if-else·防御性编程