Linux:基础IO

引言:

C语言是怎样进行文件操作的?

#include<stdio.h>
#include<string.h>
int main(){
FILE* fp=fopen("test.txt","w");
if(!fp){
printf("fopen error!\n");
}
const char msg="hello world\n";
int count=5;
while(count--){
fwrite(msg,strlen(msg),1,fp);
}
close(fp);
return 0;
}

对文件的读写需要用到 fopen、fread、fwrite 等系统底层函数,而用户进程每调用一次系统函数都要从用户态切换到内核态,等执行完毕后再返回用户态,这种切换要花费一定时间成本(对于高并发程序而言,这种状态的切换会影响到程序性能)。

读取文件:

#include <stdio.h>
#include <string.h>
int main()
{
	FILE* fp = fopen("test.txt", "r");
	if (!fp)
	{
		printf("fopen error!\n");
	}
	char buf[1024];
	const char* msg = "hello world!\n";
	while (1)
	{
		size_t s = fread(buf, 1, strlen(msg), fp);
		if (s > 0)
		{
			buf[s] = 0;
			printf("%s", buf);
		}
		if (feof(fp))
		{
			break;
		}
	}
	fclose(fp);
	return 0;
}

fread是将文件的数据读到缓冲区里

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

buffer是自己设定的缓冲区

size是要读取数据的大小,char就是1,int就是4

count是要读取的个数

stream是文件指针

返回值是实际从文件中读取的基本单元个数

feof用检测流上的文件结束符:如果遇到文件正常结束,函数返回值为非零值;如果文件异常结束,函数返回值值为0。

C程序在启动的时候会默认启动三个输入输出流,他们分别是:

extern FILE* stdin;           //键盘
extern FILE* stdout;          //显示器,可以打印到显示器上
extern FILE* stderr;           //标准错误,收集错误,也属于显示器

他们三个在代码层面上都是文件指针的类型,也就是*FILE

很多情况下,操作系统中存在着许多被同时打开的文件。这些被打开的文件都是由磁盘打开的,操作系统需要对文件进行管理。

如何管理?

通过某种描述文件属性的数据结构,最后转换成指针之间的映射;从操作文件改为操作指针

文件=属性+内容,

以w打开文件的话,文件如果不存在,就在当前路径下新建指定文件,且默认打开文件的时候会把目标文件先清空

输出重定向伴随着文件操作

理解文件

操作文件的本质是进程在操作文件

文件一开始在磁盘上,本质上在硬件部分的存储

但是用户没有权利直接写入,操作系统是硬件的管理者,用户需要通过操作系统进行写入

操作系统为我们提供系统调用的接口,用的是C/C++对系统调用接口的封装

访问文件也是通过系统调用来访问的

系统如何访问

open:

open 系统调用中,flags 是一个由多个标志位组合而成的整数,常见的标志包括:

  • O_RDONLY: 以只读模式打开文件。
  • O_WRONLY: 以只写模式打开文件。
  • O_RDWR: 以读写模式打开文件。
  • O_CREAT: 如果文件不存在,则创建文件。需要指定 mode 参数。
  • O_EXCL: 如果文件已经存在,则返回错误(与 O_CREAT 一起使用)。
  • O_TRUNC: 如果文件已存在,并且以写模式打开,则将文件截断为零长度。
  • O_APPEND: 以追加模式打开文件,将数据写入文件末尾。

系统的接口:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
 
int main()
{
	int fd = open("log.txt", O_WRONLY | O_CREAT);
	if (fd < 0)
	{
		perror("open fail");
		return 1;
	}
	return 0;
}

执行一下:

 在Linux中创建文件的时候要告诉它起始权限,否则将会是乱码 

这样改:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
 
int main()
{
	int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
	if (fd < 0)
	{
		perror("open fail");
		return 1;
	}
	return 0;
}

最后的权限是由我们给定的起始权限和umask掩码共同决定的

umask掩码也可以

我们自己设定:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
 
int main()
{
	umask(0);//修改umask
	int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
	if (fd < 0)
	{
		perror("open fail");
		return 1;
	}
    close(fd);//记得关掉
	return 0;
}

关闭文件的接口:

open函数中的第二个参数:O_WRONLY | O_CREAT是宏,代表的是打开文件以读取模式

还有别的:O_WRONLY只写;O_RDWR,读写

open会 返回一个文件描述符(非负整数),用于后续的读写操作。打开文件后,记得使用

在操作系统设计中,系统调用接口可能会用到标志位来指示特定的功能或选项。使用比特位传递标志位可以有效地利用每个整数的多个位,从而在一个整数中存储多个独立的标志位,理解下来其实就像用二进制来表示还是

这种做法提高了效率,并减少了需要传递的数据量。例如,一个32位的整数可以用32个位来表示32个不同的标志位,这样只需传递一个整数,就可以传递多个开关状态。

我们也可以自己写一个具有这种传递位图标记位的函数:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
 
#define ONE 1
#define TWO (1<<1)
#define THREE (1<<2)
#define FOUR (1<<3)
 
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(ONE | TWO);
	printf("\n");
	Print(ONE | TWO | THREE);
	printf("\n");
	Print(ONE | TWO | THREE | FOUR);
	printf("\n");
	return 0;
}

可以用标记位组合的方式向一个函数传递多个标记位(比如只传递1,就只打印1;传递1、2、3和4,就启用上面函数的对应部分)

我们把文件打开以后就涉及到写入了

写入的接口函数是:write

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
	umask(0);
	int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
	if (fd < 0)
	{
		perror("open fail");
		return 1;
	}
 
	const char* message = "Hello Linux file\n";
	write(fd, message, strlen(message));
	close(fd);
	return 0;
}

执行结果:

注意:当出现这个提示的时候说明文件权限对于你来说没有“写”权限,需要自己chmod设置一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值