嵌入式之路,贵在日常点滴
---阿杰在线送代码
目录
用fopen、fread、fwrite、fseek来给一个文件写入结构体
一、系统调用
1.1 什么是系统调用
系统调用函数属于操作系统的一部分,是为了提供给用户进行操作的接口(API函数),使得用户态运行的进程与硬件设备(如CPU、磁盘、打印机、显示器)等进行交互。
- 例如常见的系统调用 等等write read open …
1.2 什么是库函数
- 库函数可分为两类,一类是C语言标准库函数,一类是编译器特定的库函数。
- 库函数可以理解为是对系统调用函数的一层封装。尽管系统函数执行效率是比较高效而精简的,但有时我们需要对获取的信息进行更复杂的处理,或更人性化的需要,我们把这些处理过程封装成一个函数,再将许多这类的函数放在一个文件(库)一般放在 .lib文件。最后再供程序员使用。
- #include<stdio.h>使用的时候包含头文件就可以使用其中的库函数了
- 例如常见的库函数printf fwrite fread fopen…等等
1.3 将hello写入到文件1.txt流程
- 首先fopen打开文件 fwrite参数附上要写入的内容
- 文本内容来到C标准缓冲区
- 如果满足条件就刷新C标准缓冲区,调用系统函数write进行写(补充:满了就会自动刷新)
- write却只是把要写入的内容写到内核缓冲区
- 如果内核缓冲区满足条件就刷新内核缓冲区,系统调用sys_write将缓冲区内容写入到磁盘(补充:有个进程会定时刷新内核缓冲区)
- 此时有进程读取1.txt文件内容,发现内核缓冲区就有这个文件内容,就直接从内核缓冲区
1.4 为什么要有缓冲区(补充)
定义:缓冲区就是内存里的一块区域,把数据先存内存里,然后一次性写入硬盘中的文件,类似于数据库的批量操作。
好处:减少对硬盘的直接操作,硬盘的执行速度为毫秒级别,内存为纳秒级别。在硬盘直接操作读写效率太低。
1.5 内核缓冲区和C标准缓冲区的区别
C语言标准库函数fopen()每打开一个文件时候,其都会对应一个单独一个缓冲区而内核缓冲区是公用的。
二、文件编程常用API
1、文件打开 open()
1.1 函数原型
- .int open(const char *pathname, int flags);
- .int open(const char *pathname, int flags, mode_t mode);
1.2 参数描述
- .pathname :文件路径+文件名(若不包含路径,则默认为当前路径)
- .flats : (1) O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 可读可写打开
(2)当我们附带了权限后,打开的文件就只能按照这种权限来操作。
以上这三个常数中应当只指定一 个。下列常数是可选择的:
O_CREAT 若文件不存在则创建它。使用此选项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限。
O_EXCL 如果同时指定了OCREAT,而文件已经存在,则出错。
O_APPEND 每次写时都加到文件的尾端。
O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。
当然也有组合使用(1.O_RDONLY |O_CREAT 只读如果不存在则创建)(O_WRONLY |O_CREAT 只写如果不存在则创建)(O_WRONLY | O_APPEND 文件存在则追加写入)
- .mode:一定是在flags中使用了O_CREAT标志,mode记录待创建的文件的访问权限
- . 返回值: 失败返回-1,成功返回 整形(fd:文件描述符)
fd>0,文件打开成功且fd为文件标识符 fd<0,文件打开失败*/
1.3代码举例
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stdio.h"
int main()
{
int fd;//file description
fd = open("./file1",O_RDWR);
printf("fd = %d\n",fd);
return 0;
}
运行结果:
下面对flags(2)这类使用(|
)进行附加使用的参数进行额外说明:
(1)O_CREAT:文件若不存在则创建
注意:需要额外说明文件操作权限参数mode
include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stdio.h"
int main()
{
int fd;//file description
//尝试打开当前路径下的文件file1.c
fd = open("./file1",O_RDWR);
//打开失败了
if(fd == -1){
printf("open file1 failed,fd = %d\n",fd);
//尝试以可读可写的方式创建并打开文件
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd > 0){
printf("create file1,fd = %d\n",fd);
}
}
return 0;
}
运行结果:可以看到已经成功创建了file1.c
(2)O_EXCL:如果同时指定了OCREAT,而文件已经存在,则出错(返回值为-1)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stdio.h"
int main()
{
int fd;//file description
fd = open("./file1",O_RDWR|O_CREAT|O_EXCL,0600);
if(fd == -1){
printf("file1 cunzai\n");
}
return 0;
}
运行结果:
(3)O_APPEND:每次写时都加到文件的尾端(另起一行)
如果不使用这个参数,因为文件打开后光标是位于文件头的,写入数据会把原来的数据按长度覆盖。(本质上就是光标的问题)
原file1内容
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stdio.h"
#include <unistd.h>
#include "string.h"
int main()
{
int fd;//file description
char *buf = "a jie hen shuai";
fd = open("./file1",O_RDWR|O_APPEND);
printf("open suscess:fd = %d\n",fd);
int n_write = write(fd,buf,strlen(buf));
if(n_write != -1){
printf("write %d byte to file\n",n_write);
}
close(fd);
return 0;
}
运行后
若不加O_APPEND
(4)O_TRUNC清空原内容后写入
在每次打开文件写入之前,先把原有的内容清空后写入
原file1内容
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stdio.h"
#include <unistd.h>
#include "string.h"
int main()
{
int fd;//file description
char *buf = "a jie hen shuai";
fd = open("./file1",O_RDWR|O_TRUNC);
printf("open suscess:fd = %d\n",fd);
int n_write = write(fd,buf,strlen(buf));
if(n_write != -1){
printf("write %d byte to file\n",n_write);
}
close(fd);
return 0;
}
运行后:
附:关于mode
1、可读 r 4
2、可写 w 2
3、执行 x 1
创建文件 creat()
创建文件的另一种方法(不可用于打开)
int creat(const char *pathname, mode_t mode);
/** mode **
S_IRUSR 可读 宏:4
S_IWUSR 可写 宏:2
S_IXUSR 可执行 宏:1
S_IRWXU 可读可写可执行 宏:7 */
简单使用示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
//可读可写
int fd = creat("./file1.c",S_IRUSR|S_IWUSR);
if(fd > 0){
printf("文件创建成功\n");
}else{
printf("同名文件已经存在\n");
}
close(fd);
return 0;
}