【Linux系统编程】第二十六弹---彻底掌握文件I/O:C/C++文件接口与Linux系统调用实践

小林熬夜学编程 2024-10-04 08:35:01 阅读 90

✨个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】

目录

1、回顾C语言文件接口

1.1、以写的方式打开文件

1.2、以追加的方式打开文件

2、初步理解文件

2.1、C++文件接口

3、进一步理解文件

3.1、系统调用实现写方式打开文件

3.2、系统调用实现追加打开文件

 3.3、理解open第二个参数原理


1、回顾C语言文件接口

1.1、以写的方式打开文件

1、如果文件不存在,就在当前路径下新建指定的文件。

2、默认打开文件的时候,会先清空文件 ->  等价于 >输出重定向。

代码演示一

<code>#include<stdio.h>

int main()

{

// 以写方式打开文件

FILE* fd = fopen("log.txt","w");

if(fd == NULL)

{

perror("fopen");

return 1;

}

// 向文件写内容

fprintf(fd,"helloworld,%d,%s,%lf\n",10,"abcd",3.14);

// 关闭文件

fclose(fd);

return 0;

}

运行结果 

 

代码演示二 

<code>#include<stdio.h>

int main()

{

// 以写方式打开文件

FILE* fd = fopen("log.txt","w");

if(fd == NULL)

{

perror("fopen");

return 1;

}

fclose(fd);

return 0;

}

运行结果 

看一段命令

<code>[jkl@host file]$ cat log.txt

helloworld,10,abcd,3.140000

[jkl@host file]$ echo "hello linux" > log.txt

[jkl@host file]$ cat log.txt

hello linux

[jkl@host file]$ > file.txt

[jkl@host file]$ ls

file.txt log.txt makefile myfile myfile.c

[jkl@host file]$ cat log.txt

hello linux

[jkl@host file]$ >log.txt

[jkl@host file]$ cat log.txt

[jkl@host file]$

解析命令

结论:

重定向 > 可以创建新文件和清空文件内容。 

1.2、以追加的方式打开文件

1、如果文件不存在,就在当前路径下新建指定的文件。

2、默认打开文件的时候,会在末尾追加内容 ->  等价于 >>输出重定向。

 代码演示

<code>#include<stdio.h>

int main()

{

// 以追加的方式打开文件

FILE* fd = fopen("log.txt","a");

if(fd == NULL)

{

perror("fopen");

return 1;

}

fprintf(fd,"helloworld,%d,%s,%lf\n",10,"abcd",3.14);

fclose(fd);

return 0;

}

运行结果 

看一段命令 

<code>[jkl@host file]$ ./myfile

[jkl@host file]$ cat log.txt

helloworld,10,abcd,3.140000

helloworld,10,abcd,3.140000

helloworld,10,abcd,3.140000

[jkl@host file]$ cat myfile.c

[jkl@host file]$ echo "hello linux" >> log.txt

[jkl@host file]$ cat log.txt

helloworld,10,abcd,3.140000

helloworld,10,abcd,3.140000

helloworld,10,abcd,3.140000

hello linux

[jkl@host file]$ >> file1.txt

[jkl@host file]$ ls

file1.txt file.txt log.txt makefile myfile myfile.c

解析命令 

结论: 

>> 追加重定向可以创建新文件和追加文件内容。 

2、初步理解文件

文件 = 属性 + 内容打开文件:本质是进程(struct task_struct)打开文件(struct xxx)文件没有打开的时候,存放在哪里?硬盘。进程能打开很多文件吗?可以系统能否存在很多进程?可以很多情况下,OS内部存在大量被打开的文件 -> OS是否要将被打开的文件进行管理 -> 怎么管理呢?先描述在组织 -> 预言:每一个被打开的文件,在OS内部,一定要存在对应的描述文件属性的结构体,类似于PCB。

2.1、C++文件接口

以写的方式打开文件。

代码演示

<code>#include<iostream>

#include<fstream>

#include<string>

#define FILENAME "log.txt"

int main()

{

// out写方式 in读方式 app追加 binary二进制

std::ofstream out(FILENAME,std::ios_base::out);

// is_open() 检查文件是否打开

if(!out.is_open()) return 1; //打开失败,结束程序

std::string msg = "hello C++!\n";

// ostream& write (const char* s, streamsize n);

out.write(msg.c_str(),msg.size());

// 关闭文件

out.close();

return 0;

}

运行结果 

3、进一步理解文件

操作文件:本质是进程在操作文件,即进程与文件的关系。

文件 ->存储在硬盘中 -> 硬盘是一个外设 -> 外设是一个硬件 -> 向文件中写入本质是向硬件中写入 -> 用户没有权利直接写入 -> OS是硬件的管理者 -> 通过OS写入 -> OS必须给我们提供系统调用(因为OS不相信任何人) -> fopen/fwrite/fread/fclose ... -> 我们用的都是C/C++/... 对系统调用接口的封装! -> 访问文件,我们也可以直接使用系统调用!!!

为什么要对系统调用的接口进行封装?怎么封装?

后序回答。

使用系统调用接口来操作文件!!!

系统调用接口函数

打开文件

<code>#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

pathname:

要打开或创建的目标文件

flags:

打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。

mode:

设置默认权限信息。

参数:

O_RDONLY: 只读打开

O_WRONLY: 只写打开

O_RDWR : 读,写打开

这三个常量,必须指定一个且只能指定一个

O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限

O_APPEND: 追加写

O_TRUNC : 若文件存在会先清空文件

返回值:

成功:新打开的文件描述符

失败:-1

向文件中写内容 

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

将缓冲区指向的 buf 内容中的count个字节数写入到文件描述符 fd 引用的文件。 

关闭文件 

#include <unistd.h>

int close(int fd);

关闭文件描述符 fd 引用的文件。

3.1、系统调用实现写方式打开文件

系统调用可能用到的头文件

#include<stdio.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<string.h>

#include<unistd.h>

代码演示一(不设置权限信息)

int main()

{

int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC);

if(fd < 0)

{

perror("open");

return 1;

}

// ssize_t write(int fd, const void *buf, size_t count);

const char* msg = "hello linux file!\n";

write(fd,msg,strlen(msg));

close(fd);

return 0;

}

运行结果

上面的代码演示的是文件不存在,在当前路径创建指定文件,但没有设置默认权限的情况。 

代码演示一(只设置权限信息)

<code>int main()

{

int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);

if(fd < 0)

{

perror("open");

return 1;

}

// ssize_t write(int fd, const void *buf, size_t count);

const char* msg = "hello linux file!\n";

write(fd,msg,strlen(msg));

close(fd);

return 0;

}

运行结果 

上面的代码演示的是文件不存在,在当前路径创建指定文件,且设置默认权限的情况。  

 想要第三个参数是什么权限文件就是什么权限应该怎么办呢???

将umask值设置为0即可。

<code>#include <sys/types.h>

#include <sys/stat.h>

mode_t umask(mode_t mask);

设置umask值。

代码演示三(设置权限信息和umask)

int main()

{

umask(0);

int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);

if(fd < 0)

{

perror("open");

return 1;

}

// ssize_t write(int fd, const void *buf, size_t count);

const char* msg = "hello linux file!\n";

write(fd,msg,strlen(msg));

close(fd);

return 0;

}

运行结果 

上面的代码演示的是文件不存在,在当前路径创建指定文件,且设置默认权限和umask的情况。   

代码演示四

<code>int main()

{

umask(0);

int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0777);

if(fd < 0)

{

perror("open");

return 1;

}

close(fd);

return 0;

}

 运行结果

上面的代码演示的是文件存在,先清空文件内容,即使修改默认权限,也不会影响该文件的权限。   

3.2、系统调用实现追加打开文件

代码演示

<code>int main()

{

umask(0);

int fd = open("log.txt",O_WRONLY | O_CREAT | O_APPEND,0666);

if(fd < 0)

{

perror("open");

return 1;

}

// ssize_t write(int fd, const void *buf, size_t count);

const char* msg = "hello linux file!\n";

write(fd,msg,strlen(msg));

close(fd);

return 0;

}

运行结果

 3.3、理解open第二个参数原理

原理是位图加位运算,下面通过一个程序理解调用open第二个参数原理。

代码演示 

<code>#define ONE 1 // 0000 0001

#define TWO (1<<1) // 0000 0010

#define THREE (1<<2) // 0000 0100

#define FOUR (1<<3) // 0000 1000

void print(int flag)

{

if(flag & ONE)

{

printf("one\n");

}

if(flag & TWO)

{

printf("two\n");

}

if(flag & THREE)

{

printf("three\n");

}

if(flag & FOUR)

{

printf("four\n");

}

}

int main()

{

print(ONE);

printf("\n");

print(TWO);

printf("\n");

print(ONE | TWO);

printf("\n");

print(ONE | TWO | THREE);

printf("\n");

print(ONE | TWO | THREE | FOUR);

printf("\n");

return 0;

}

运行结果 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。