进程基础IO
(IO接口的基本认识和使用,文件描述符与重定向,静态库与动态库的生成和使用)
先复习一下C语言的文件操作
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE* fp = fopen("hello", "w+");
if (!fp)
{
perror("fopen error");
exit(0);
}
const char* str = "hello bit\n";
int count = 5;
while (count--)
fwrite(str, strlen(str), 1, fp);
printf("ftell=%d\n",ftell(fp));
char buf[11];
fread(buf, 1, 10, fp);
//读取不到任何内容,因为此时文件指针指向文件结尾,应该让其回到文件首
printf("buf=%s\n", buf);
rewind(fp);
printf("ftell=%d\n", ftell(fp));
char buf2[11] = { 0 };
fread(buf2, 1, 10, fp);
printf("buf2=%s\n", buf2);
fclose(fp);
}
运行结果
库函数
常用文件操作函数:
FILE *fopen( const char *filename, const char *mode );//打开文件
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );//写
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );//读
int fseek( FILE *stream, long offset, int origin );//移动文件指针到指定位置
origin有三个可选参数分别是文件起始、当前读写、文件末尾位置:SEEK_SET(0) ; SEEK_CUR(1) ; SEEK_END(2)
void rewind( FILE *stream );//将文件指针重新定位到文件的开头
int fclose( FILE *stream );//关闭stream
int _fcloseall( void );//关闭全部open的streams
int fflush( FILE *stream );
文件打开方式:r(读),w(写),a(追加写),+(读写),每种打开方式的文件指针初识是不同的
系统调用接口
系统调用IO接口:
库函数是对系统调用接口的封装
接口open、write、read、lseek、close
系统调用接口比较单一,在某些特定场景下使用比较麻烦,所以有库函数对其封装
类似的像exit(库函数)和_exit(系统调用接口)
对于系统调用接口根本不存在缓冲区,只是库函数对文件描述符做了一个改进:添加了缓冲区
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
int main()
{
umask(0);
ssize_t fd=open("1.txt",O_TRUNC|O_RDWR|O_CREAT,0777);//创建,截断,读写,设置文件权限
if(fd<0)
{
perror("open error");
return -1;
}
char str[]="hello world\n";
//ssize_t write()(int fd, char* buf, size_t len);成功返回写入字节长度,失败-1
//fd:open打开文件是返回的操作句柄--文件描述符
ssize_t ret=write(fd,str,strlen(str));
if(ret<0)
{
perror("write error");
close(fd);
return -1;
}
//lseek(int fd, off_t offset, int whence);
lseek(fd,0,0);//返回文件头
char buf[100];
ret=read(fd,buf,100);//成功返回实际读到长度,0--到达文件末尾,没有读到数据,-1出错
if(ret<0)
{
perror("read error");
}
printf("%s",buf);
int size=lseek(fd,0,SEEK_END);
printf("文件大小:%u\n",size);
close(fd);
return 0;
}
重定向
文件描述符fd:被打开文件的操作句柄–是一个非负整数
本质上是个数组下标,对应的数组保存的是进程打开的文件的描述信息
当操作文件的时候需要传入描述符,其实就是通过这个下标找到对应文件的描述信息,进而操作文件
重定向:
将一个描述符所对应位置的文件描述信息地址,替换成另一个文件的描述
调用dup函数,内核在进程中创建一个新的文件描述符(句柄),此描述符是当前可用文件的描述符最小值,这个新的描述符指向oldfd所拥有的文件表项
重定向:dup(int oldfd);//无法指定newfd的值
dup2(int oldfd, int newfd);//可以指定newfd,如果newfd被占用,就关闭它之前的连接,再让其指向oldfd
_dup, _dup2
Create a second handle for an open file (_dup), or reassign a file handle (_dup2).
int_dup( int handle );
int _dup2( int handle1, int handle2 );
_dup和_dup2函数将第二个文件句柄与当前打开的文件相关联。这些函数可用于将预定义的文件句柄(例如stdout的句柄)与其他文件相关联。可以使用任一文件句柄对文件执行操作。文件允许的访问类型不受创建新句柄的影响_dup返回给定文件的下一个可用文件句柄。_dup2强制handle2引用与handle1相同的文件。如果handle2在调用时与打开的文件关联,则该文件被关闭。
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
void main(void)
{
int old;
FILE *new;
old = _dup(1);//创建新句柄3,句柄指向stdout
/* Note: file handle 1 == "stdout" */
if (old == -1)
{
perror("_dup( 1 ) failure");
exit(1);
}
write(old, "This goes to stdout first\r\n", 27);//向old句柄(此时已是stdout),写
if ((new = fopen("data.txt", "a")) == NULL)//打开文件,new接收文件描述符
{
puts("Can't open file 'data'\n");
exit(1);
}
/* stdout now refers to file "data" */
if (-1 == _dup2(_fileno(new), 1))//让1(stdout)指向new,达到重定向
{
perror("Can't _dup2 stdout");
exit(1);
}
puts("This goes to file 'data'\r\n");//此时的puts不会输出控制台,会写入文件
/* Flush stdout stream buffer so it goes to correct file */
fflush(stdout);
fclose(new);
/* Restore original stdout */
_dup2(old, 1);//让1句柄指回stdout,old保存stdout
puts("This goes to stdout\n");
puts("The file 'data' contains:");
system("type data");
}