Linux/AP_Autosar/C++系列之 linux系统调用下的IO
“ 一步一步走,日坤月累,2023走到最下面”
文件描述符
在linux中,一切皆为文件,无论是对文件还是对设备进行操作,实际上都是对文件进行操作。
当打开或者创建文件时,内核向进程返回的是一个文件描述符。会有三种情况返回。
- 标准输入 0 STDIN_FILENO
- 标准输出 1 STDOUT_FILENO
- 标准错误 2 STDERR_FILENO
这个宏定义在头文件
unistd.h
文件的打开,创建,与关闭
- 文件的打开
#include <fcntl.h>
int open(const char *path, int flags);
int open(const char *path, int flags, mode_t mode);
open()函数的第一个参数是要打开或创建的文件的路径。
flags参数是一个整数,用于指定文件的打开方式和属性。它可以通过使用不同的标志位来组合实现不同的功能,常见的标志位包括:
- O_RDONLY:只读方式打开文件
- O_WRONLY:只写方式打开文件
- O_RDWR:读写方式打开文件
- O_CREAT:如果文件不存在则创建文件
- O_TRUNC:如果文件存在,将文件长度截断为0
- O_APPEND:追加方式打开文件,在文件末尾写入数据
- O_EXCL:与O_CREAT一起使用,确保新创建的文件不存在,如果文件已存在则打开失败
mode参数用于指定新创建文件的权限。
open()函数返回一个文件描述符(非负整数),如果打开或创建文件失败,则返回-1。我们可以使用这个文件描述符来进行后续的读写操作。
#include <fcntl.h>
#include <unistd.h>
int main() {
char buffer[4096];
int fileDescriptor = open("example.txt", O_RDONLY);
if (fileDescriptor == -1) {
// 打开文件失败
return -1;
}
return 0;
}
- 文件的创建
注意这个不是create, 二十creat. 我也不知道为什么没有e.
#include <fcntl.h>
int creat(const char *path, mode_t mode);
creat()函数接受两个参数:
- path:要创建的文件的路径和名称。
- mode:指定新创建文件的权限。
creat()函数返回打开的文件描述符,如果创建文件失败,则返回-1。
#include <fcntl.h>
#include <unistd.h>
int main() {
int fileDescriptor = creat("example.txt", 0666);
if (fileDescriptor == -1) {
// 创建文件失败
return -1;
}
return 0;
}
- 文件的关闭
#include <unistd.h>
int close(int fd);
close()函数接受一个整数参数fd,表示要关闭的文件描述符。
close()函数返回一个整数值,如果关闭文件成功,则返回0;如果发生错误,则返回-1。
#include <fcntl.h>
#include <unistd.h>
int main() {
int fileDescriptor = open("example.txt", O_RDWR);
if (fileDescriptor == -1) {
// 打开文件失败
return -1;
}
int closeResult = close(fileDescriptor);
if (closeResult == -1) {
// 关闭文件失败
return -1;
}
return 0;
}
文件的读取与写入
这里我们先在试验台随便创建一个dat文件如下图。
现在我们通过上面所学的来读取里面的内容。
#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd = -1;
ssize_t size = -1;
char buf[10];
char filename[] = "./data.dat";
fd = open(filename,O_RDONLY);
if(fd == -1)
{
printf("file open failure\n");
return -1;
}else
{
printf("file open success \n");
while(size)
{
size = read(fd,buf,10);
if(-1 == size)
{
printf("error happen \n");
close(fd);
return -1;
}else
{
if(size > 0)
{
printf("read data size is %ld: \n", size);
printf("\"");
for(int i =0; i<size; i++)
{
printf("%c ",buf[i]);
}
printf("\"\n");
}else
{
printf("no data any more \n");
}
}
}
}
}
看着有点错乱,这个是因为每一行最后巧了enter, 被识别成
两个空字符。不影响代码阅读
文件的写入
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
这里我们用write来写入一个文件。
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main() {
int fileDescriptor = open("example.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fileDescriptor == -1) {
// 打开文件失败
return -1;
}else{
printf("file created and opened\n");
}
const char *text = "Hello, world!";
ssize_t bytesWritten = write(fileDescriptor, text, strlen(text));
if (bytesWritten == -1) {
// 写入文件失败
return -1;
}
close(fileDescriptor);
return 0;
}
文件的偏移量
文件的读写我们学会了,但是一般使用中,肯定不是只有从头或者从尾开始,而是需要移动鼠标到指定的文件位置。这里我们学习一下lseek.
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
lseek()函数接受三个参数:
- fd:要操作的文件描述符。
- offset:根据whence参数来确定偏移量的值。可以是正值、负值或者0。
- whence:指定偏移量的基准位置,可以使用以下常量:
○ SEEK_SET:从文件开头开始计算偏移量。
○ SEEK_CUR:以当前位置为基准计算偏移量。
○ SEEK_END:以文件末尾为基准计算偏移量。
还是用上一个代码,加了点lseek.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
off_t offset =-1;
int fileDescriptor = open("example.txt", O_RDWR);
if (fileDescriptor == -1) {
// 打开文件失败
return -1;
}else{
printf("file created and opened\n");
}
// const char *text = "Hello, world!";
const char *text = "facaile";
//在这里面添加偏移
offset = lseek(fileDescriptor,5,SEEK_SET); //从头数5个
ssize_t bytesWritten = write(fileDescriptor, text, strlen(text));
if (bytesWritten == -1) {
// 写入文件失败
return -1;
}
close(fileDescriptor);
return 0;
}
文件与内存
文件和内存映射,这里是把文件映射到内存中。
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
mmap()函数接受六个参数:
- addr:指定映射的起始地址。通常设置为NULL,由操作系统决定实际的地址。
- length:映射的长度,以字节为单位。
- prot:指定映射的保护方式,可以使用以下标志的组合:
○ PROT_NONE:页面不可访问。
○ PROT_READ:页面可读。
○ PROT_WRITE:页面可写。
○ PROT_EXEC:页面可执行。
- flags:指定映射的特性,可以使用以下标志的组合:
○ MAP_SHARED:映射区域与文件关联,对映射区域的更改会反映到文件中。
○ MAP_PRIVATE:映射区域与文件关联,但对映射区域的更改不会反映到文件中。
○ MAP_ANONYMOUS:创建匿名映射,不与文件关联。
○ MAP_FIXED:强制将映射区域放置在特定地址处。
- fd:要映射到内存的文件描述符。如果指定了MAP_ANONYMOUS标志,则应为-1。
- offset:文件中的偏移量,表示映射的起始位置。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main() {
int fileDescriptor = open("example.txt", O_RDONLY);
if (fileDescriptor == -1) {
// 打开文件失败
return -1;
}
struct stat fileInfo;
if (fstat(fileDescriptor, &fileInfo) == -1) {
// 获取文件信息失败
close(fileDescriptor);
return -1;
}
off_t fileSize = fileInfo.st_size;
// 映射文件到内存
void *mappedAddress = mmap(NULL, fileSize, PROT_READ, MAP_PRIVATE, fileDescriptor, 0);
if (mappedAddress == MAP_FAILED) {
// 映射文件失败
close(fileDescriptor);
return -1;
}
// 读取内存映射的文件数据
char *data = (char *)mappedAddress;
for (off_t i = 0; i < fileSize; i++) {
printf("%c", data[i]);
}
return 0;
}
文章转载自公众号:汽车与基础软件