[Linux]--基础I/O

[Linux]–基础IO

今天在复习的时候,看到Linux的基础I/O,觉得自己有必要再整理下思路,回顾基础I/O的操作。
在这里先写两个关于C语言标准库的输入输出文件的代码

回顾下C语言中的标准库I/O

向Test.c里面写文件

#include <stdio.h>
#include <string.h>

int main()
{
 	FILE *fp=fopen("myfile.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);
	}
	fclose(fp);
	return 0;
	}

向Test.c里面读文件

#include <stdio.h>
#include <string.h>

int main()
{
	FILE *fp=fopen("myfile.txt","r");
	if(!=fp)
	{
		printf("fopen error\n");
	}
	char buff[1024];
	const char*msg="hello world";
	while(1)
	{
	ssize_t s=fread(buff,1,strlen(msg),fp);
	if(s>0)
	{
		buff[s]=0;
		printf("%s",buff);
	}
		if(feof(fp)
		{
		break;
		}
	}
	fclose(fp);
	return 0;
	}		

亲测以下三种C语言方法可以将内容打印到屏幕上

#include <stdio.h>
#include <string.h>

int main()
{
	const char*msg="1:hello world\n";
	fwrite(msg,strlen(msg),1,stdout);
	printf("2:hello world\n");
	fprintf(stdout,"3:hello fprintf\n");
	return 0;
}

输出的结果是:
1:hello world
2: hello world
3:hello world
准确的说C语言会默认有三个输入输出流,分别是stdin,stdout和stderr
用man手册会发现,这三个流的类型都是FILE*。

系统文件I/O

可以看见,操纵文件除了上述的c接口,c++也同样可以。那Linnux下,设备都是以文件的形式存在的,那当我们要运用这些设备,就是要打开这些文件。那在Linux下我们是如何进行文件的访问呢?
首先是打开文件:
(1) open函数原型:
int open(const char*pathname,int flags,mode_t mode);
函数头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
参数:
pathname:打开或者创建的文件名字,如“myfile.txt";
flags:表示你要进行的操作方式。主要有O_RDONLY(只读),O_WRONLY(只写),O_RDWR(读写),O_PPEND(追加写),O_CREAT(创建一个文件),O_TRUNC (打开文件的时候清空原有数据)。其中前三种为必选选项,后三种为可选选项。(当然还有很多选项,读者可自行查阅,这里只列举出常用的几种)
mode:你要创建当前文件的操作权限码,只有在创建的时候,这个参数才会派上用场
返回值:
失败返回-1,成功返回一个非负整数(即文件描述符打开文件的操作句柄,后面会讲到)

(2) close函数原型
int close(int fd);
头文件:`#include <unistd.h>
参数:这里的参数没什么好说的,调用open后返回的文件操作符
(3) 读取文件
头文件:#include <unistd.h>
函数原型:
ssize_t read(int fd,void buf,size_t count);
参数:
fd:调用open后返回的文件操作符
buf:用来存放从文件中独到的数据的缓冲区
count:读取的字节数
返回值:
成功返回独到的字节数,如果读到文件尾端,则返回0,失败返回-1
(4)写数据
头文件:#include <unistd.,h>
函数原型:ssize_t write(int fd,const void
buf,size_t count);
参数:
fd:调用open后返回的文件描述符
buf:从未存放数据的缓冲区
count:写入数据的字节数
*返回值:*成功返回已写的字节数,失败返回-1

代码实现

如果说我们要实现开头所说的向Test.c里面写文件,该怎么办呢?这就要用到我们刚才所讲的知识点了,话不多说上代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcnl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	umask(0);
	int fd=open("myfile.txt",O_WRONLY|O_CREAT,0644);
	if(fd<0)
	{
	perror("open error\n");
	return -1;
	}
	int count=5;
	const char*msg="hello world\n";
	int len=strlen(msg);
        while(count--)
        {
        	write(fd,msg,len);
     	}
     	close(fd);
     	return 0;
}

umask是指每次都将文件的权限设置为0

文件描述符

通过对open函数的学习,我们知道文件描述符是一个非负整数,那么他到底是什么东西,能够有这样的能力使我们访问到文件呢?
简单的说,文件操作符就是文件的操作句柄,其实在之前我们还提到过c语言中,标准的输入输出分别是:stdin,stdout,stderr,这刚好就相对于我们的三个文件描述符:0对应的是标准输入,1对应的是标准输出,2对应的是标准错误。因此,一般打开一个现有文件或者创建一个新文件的时候,内核向进程返回一个文件描述符,而也就明白了为什么打开一个文件,文件描述符都是从3开始的,因为前三个已经被占用了。
在这里插入图片描述
当我们打开一个文件的时候,在Linux内核中通常会有个task_struct结构体来维护进程相关的表,叫做进程控制块,这个块里面会有一个*file指针指向file_struct的结构体,称为文件描述符表,这个表中包含的是一个指针数组,里面的元素就是指向打开文件的指针,一般情况下,进程是没有办法直接访问文件的,只能通过文件描述符,就是这个表的索引来找到文件。

重定向

先来看一段代码:

#include  <stdio.h>
#include <sys/type.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	close(0);
	//close(2);
	int fd=open("myfile.txt",O_RDONLY);
	if(fd<0)
	{
	perror("open file");
	return 1;
	}
	printf("fd:%d\n",fd);
	close(fd);
	return 0;
}

在这段代码中,我关闭了0(或者关闭2),发现输出是fd:0(当关闭2时,输出为fd:2),这是什么意思?就是说我们的文件操作符的分配规则就是,在file_struct数组当中,找到当前没有被使用的最小下标,作为新的文件描述符。
问题来了,那为什么不关掉1呢?

#include  <stdio.h>
#include <sys/type.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	close(1);
	int fd=open("myfile.txt",O_WRDONLY|O_CREAT,0664);
	if(fd<0)
	{
	perror("open error");
	return 1;
	}
	printf("fd:%d\n",fd);
	fflush(stdout);
	close(fd);
	return 0;
}

此时,我们发现,本来应该输出到显示器上的内容,输出到了文件myfile.txt里面,其中fd=1,这种现象叫做重定向。

在这里插入图片描述
什么意思呢?原因是因为我们关闭了1,也就是标准输出,当我们打开一个新文件的时候,会按照文件描述符的分配原则将1分配给这个文件,凡是在1号的文件描述符写的内容,都写到了myfile.txt中,而不是写到标准输出。
Linux重定向是指修改原来默认的一些东西,对原来系统命令的默认执行方式进行改变,比如说简单的我不想看到在显示器的输出,而是希望输出到某一文件中,就可以通过Linux重定向来进行这项工作。懂了吗?

发布了33 篇原创文章 · 获赞 13 · 访问量 1067

猜你喜欢

转载自blog.csdn.net/Vicky_Cr/article/details/102905445