文章目录
1.初步理解文件
🐧①
打开文件
: 本质是进程打开文件,只有程序运行起来文件才被打开;
🐧②文件没有被打开的时候在哪里呢? ----- 在磁盘中;
🐧③进程可以打开很多个文件吗? ---- 可以的🙆;
🐧④系统中可不可以存在很多个进程呢? ---- 可以存在;
🐧⑤由第3、4点可以得知,在OS内部一定存在大量的被打开的文件(如何管理呢?先描述,在组织
)
2.C语言环境下的文件操作
2.1 C库中 fopen、fwrite 的讲解
🐧①语法:
🐧②fopen () 的打开方式:
Ⅰ.✌ 以
w
的方式打开: 如果该路径下没有该文件的话,则创建该文件,如果该文件存在的话,则在打开文件的时候,把文件的内容清空;
Ⅱ.✌以a
的方式打开: 直接在该文件的后面追加内容,不会清空文件;
- 以下两个知识点是 Linux 中的概念:
Ⅲ.✌输出重定向
>
,实际上就是充当w
的作用;
Ⅳ.✌追加重定向
>>
,它实际充当的是a
的作用;
🐧② fprintf ( ) 的使用
将内容打印到 log.txt 这个文件中:
2.2 C文件操作的实例
- 三点要求如下所示: 🔍
🐧Ⅰ. 对fopen, fread, fwrite,
fseek
, fclose等函数的使用;
🐧Ⅱ.使用代码打开当前路径下的“bite”文件(如果文件不存在在创建文件),向文件当中写入“linux so easy!”.
🐧Ⅲ.在从文件当中读出文件当中的内容,打印到标准输出
当中; 关闭文件流指针;
-
代码实现如下:
🐧代码涉及的知识点如下:
🍎Ⅰ. fopen () 函数的打开方式:
🍎Ⅱ. fseek( ) 函数的讲解
大家说说 fseek( ) 函数有什么大的用处呢?
我们在向一个文件写入数据的时候,当我们写完以后,文件的读写位置就停在了写完之后的位置,当我们再对该文件进行读取的时候,读入的都是该文件
有效内容之后的数据
,导致我们无法读到我们想要的内容,而 fseek( ) 函数就可以把文件的读写位置移动到文件的开头
,我们就可以读到想要的内容啦! 😃
int fseek(FILE *stream, long offset, int whence);
offset (偏移量) : 以字节为单位;
whence(何处) :用于定义参数 offset 偏移量对应的参考值(可以理解为文件读写位置的初始值
),该参数为下列其中一种(宏定义):
SEEK_SET
:读写偏移量将指向 offset 字节位置处(从文件头部开始算);
SEEK_CUR
:读写偏移量将指向当前位置偏移量 + offset 字节位置处
, offset 可以为正、也可以为负,如果是正数表示往后偏移,如果是负数则表示往前偏移;
SEEK_END
:读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负, 如果是正数表示往后偏移、如果是负数则表示往前偏移。
🍎Ⅲ.fread ( ) 函数
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
🍎Ⅲ.fwrite ( ) 函数
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp = fopen("./bite", "wb+");
if (fp == NULL) {
perror("fopen error");
return -1;
}
// 0 表示指针指向文件的开始进行读写
fseek(fp, 0, SEEK_SET);
char *data = "linux so easy!\n";
size_t ret = fwrite(data, 1, strlen(data), fp);
if (ret != strlen(data)) {
perror("fwrite error");
return -1;
}
fseek(fp, 0, SEEK_SET);//跳转读写位置到,从文件起始位置开始偏移0个字节
char buf[1024] = {0};
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
ret = fread(buf, 1, 1023, fp);//因为设置读取块大小位1,块个数为1023因此fread返回值为实际读取到的数据长度
if (ret == 0) {
if (ferror(fp)) //判断上一次IO操作是否正确
printf("fread error\n");
if (feof(fp)) //判断是否读取到了文件末尾
printf("read end of file!\n");
return -1;
}
printf("%s", buf);
fclose(fp);
return 0;
}
3.系统调用接口的讲解
-
为什么要有系统调用呢?
🐧Ⅰ.我们对文件进行读写操作,文件是存储在磁盘
中的,而磁盘是硬件,所以向文件写入本质是向硬件写入,我们作为一个用户,操作系统绝对不允许我们对硬件直接进行访问,所以操作系统为我们提供系统调用
以便我们能够访问文件。
3.1 系统调用函数的讲解
3.1.1 open ( ) 函数的讲解
🐧① 语法:
🐧② 参数 flags 的详解
flags 表示以什么样的方式打开文件,
O_RDONLY(只读)
,O_WRONLY(只写)
, orO_RDWR(读写)
,O_APPEND(追加方式打开)
,O_TRUNC(清空文件,重新写入)
,O_CREAT(该文件不存在就创建该文件)
具体怎么使用呢? ----- 涉及到一个位图
的概念,这些O_RDONLY(只读)
已经被宏定义成为了一个值,这个值代表在二进制下某一位数字为1,然后用|
(与)操作就可以把几种方式联系到一起了;
🐧③ 参数 mode 的介绍
参数 mode 指定创建新文件时的文件权限。当参数 flags 指定标志位
O_CREAT
或O_TMPFILE
的时候,必须指定参数 mode,其他情况下忽略参数 mode。
3.1.2 write ( ) 函数的讲解
写入失败则返回
-1
3.1.3 lseek ( ) 函数的讲解
🍎Ⅰ.为什么要用 lseek ( ) 函数呢? 因为我们在使用 write ( ) 函数之后,文件的读写位置就停在了写完之后
的 \0
位置,我们再次对文件进行读取的时候就什么也读不到了,所以需要用 lseek ( ) 函数来移动文件的读写位置;
3.1.2 read ( ) 函数的讲解
3.2 用系统调用读写文件
-
要求如下三点:
🐧Ⅰ.对 open, read, write, lseek, close等函数的使用:
🐧Ⅱ.使用代码打开当前路径下的“bite”文件(如果文件不存在在创建文件),向文件当中写入“i like linux!”。
🐧Ⅲ.在从文件当中读出文件当中的内容, 打印到标准输出当中; 关闭文件描述符
#include <stdio.h>
#include <unistd.h>//是close, write这些接口的头文件
#include <string.h>
#include <fcntl.h>//是 O_CREAT 这些宏的头文件
#include <sys/stat.h>//umask接口头文件
int main()
{
//将当前进程的默认文件创建权限掩码设置为0--- 并不影响系统的掩码,仅在当前进程内生效
umask(0);
//int open(const char *pathname, int flags, mode_t mode);
int fd = open("./bite", O_CREAT|O_RDWR, 0664);
if(fd < 0) {
perror("open error");
return -1;
}
char *data = "i like linux!\n";
//ssize_t write(int fd, const void *buf, size_t count);
ssize_t ret = write(fd, data, strlen(data));
if (ret < 0) {
perror("write error");
return -1;
}
//off_t lseek(int fd, off_t offset, int whence);
lseek(fd, 0, SEEK_SET);
char buf[1024] = {0};
//ssize_t read(int fd, void *buf, size_t count);
ret = read(fd, buf, 1023);
if (ret < 0) {
perror("read error");
return -1;
}else if (ret == 0) {
printf("end of file!\n");
return -1;
}
printf("%s", buf);
close(fd);
return 0;
}