操作系统实践03—读写文件
1.打开文件
// 原型
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
功能:
-
打开已有的文件;
-
如果打开失败,返回-1;
-
如果打开成功,返回值>=0,作为被打开文件的标识符,该整数被称为文件描述符。
参数:
-
pathname:指定文件路径;
-
flags:指定打开参数,可选的取值如下;
可选值 | 说明 |
---|---|
O_RDONLY | 以只读方式打开 |
O_WRONLY | 以只写方式打开 |
O_RDWR | 以读写方式打开 |
O_APPEND | 以追加模式打开,写文件时将内容追加文件末尾 |
O_TRUNC | 如果文件存在,将文件的长度截断为0 |
O_CREAT | 如果文件不存在,创建一个新文件 |
- flags的取值可以用位或的方式进行组合
open("log.txt", O_RDWR | O_TRUNC);
2.创建文件
//原型
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
int open(const char *pathname, int flags, mode_t mode);
功能:
-
如果文件存在,则打开文件;如果文件不存在,则创建文件。
-
creat(path, mode)
和open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
等价。
返回值:
-
如果创建失败,返回-1。
-
如果创建成功,返回值>=0,作为被创建文件的标识符,该整数被称为文件描述符。
参数:
-
pathname:指定文件路径。
-
flags:指定打开参数,可选的取值与open相同。
-
mode:新建文件的访问模式。
3.关闭文件
// 原型
#include <unistd.h>
int close(int fd);
功能:
-
将打开的文件关闭;
-
操作系统需要为打开的文件分配资源,需要及时关闭不再使用的文件,从而释放相应资源。
参数:
- fd:使用open或者creat打开的文件描述符。
4.读取文件
// 原型
#include <unistd.h>
int read(int fd, void *buf, size_t count);
功能:
-
从打开的文件中读取数据到内存缓冲区;
-
如果读取失败,返回-1;
-
如果读取成功,返回实际读取的字节个数;返回0则代表读取到了文件末尾。
参数:
-
fd:使用open或者creat打开的文件描述符。
-
buf:内存缓冲区的起始位置。
-
count:内存缓冲区的长度,read的返回值小于等于count。
5.写入文件
// 原型
#include <unistd.h>
int write(int fd, void *buf, size_t count);
功能:
-
把内存缓冲区的数据写入到打开的文件;
-
如果写入失败,返回-1;
-
如果写入成功,返回实际写入的字节个数。
参数:
-
fd:使用open或者creat打开的文件描述符。
-
buf:内存缓冲区的起始位置。
-
count:内存缓冲区的长度,write的返回值小于等于count。
6.定位文件
// 原型
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能:
-
调整文件的访问位置;
-
read和write从文件的访问位置读写文件。
参数:
-
fd:使用open或者creat打开的文件描述符。
-
offset:相对于whence的位置偏移量。
-
whence:根据offset和whence设置文件访问位置,取值如下。
可选值 | 说明 |
---|---|
SEEK_SET | 文件访问位置 = offset |
SEEK_CUR | 文件访问位置 = 文件访问位置 + offset |
SEEK_END | 文件访问位置 = 文件尾部位置 + offset |
7.实践:简单数据库
实现一个简单的数据库管理系统,使用文件读写系统调用实现,可以添加记录、显示记录。
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 当系统调用失败时,调用panic函数终止程序
void panic(char *message)
{
// perror打印系统调用的报错信息
perror(message);
exit(EXIT_FAILURE);
}
// 每条记录包含两个字段:name和age
struct record {
char name[12];
int age;
};
// 全局变量,用于保存被打开数据库的文件描述符
int fd;
// 打开或者创建一个数据库
void db_open(char *path)
{
// mode指定新创建数据库文件的权限
mode_t mode = 0777;
fd = open(path, O_RDWR | O_APPEND | O_CREAT, mode);
if (fd < 0)
panic("open");
}
// 关闭数据库
void db_close()
{
close(fd);
}
// 向数据库添加记录
void db_append(char *name, int age)
{
struct record record;
strcpy(record.name, name);
record.age = age;
int count = write(fd, &record, sizeof(struct record));
if (count < 0)
panic("write");
}
// 打印记录
void db_dump(int index)
{
int offset = index * sizeof(struct record);
lseek(fd, offset, SEEK_SET);
struct record record;
int count = read(fd, &record, sizeof(struct record));
if (count != sizeof(struct record))
panic("read");
printf("name = %6s, age = %d\n", record.name, record.age);
}
int main()
{
db_open("my.db");
db_append("tom", 10);
db_append("jerry", 11);
db_append("mike", 12);
db_dump(0);
db_dump(1);
db_dump(2);
db_close();
return 0;
}
$ cc db.c
$ ./a.out
name = tom, age = 10
name = jerry, age = 11
name = mike, age = 12
$ ls -l
-rwxr-xr-x 1 root root 16960 Mar 13 02:52 a.out
-rw-r--r-- 1 root root 1000 Mar 13 02:51 db.c
-rwxr-xr-x 1 root root 48 Mar 13 02:52 my.db
在my.db
中,每条记录占用16个字节,3条记录共48字节。