Linux文件I/O

来源:互联网 发布:知乎为什么那么火 编辑:程序博客网 时间:2024/05/21 17:50

Linux文件I/O有两种实现方式:系统调用和标准函数库调用。而两种方式所操作的对象分别是文件描述符(如:STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO)和I/O流(如:stdin,stdout,stderr),这是我一个经常混淆的地方。

 系统调用中的I/O操作是一种不带缓冲的I/O方式。说到这里不得不提一下文件描述符。对于内核而言,所有打开的文件都通过文件描述符引用,也就是说它是内核的操作对象。系统调用的效率相对比较低,原因有两个:

  • 在执行系统调用时,Linux必须从用户代码切换到内核代码执行,然后返回用户代码,系统将会在此过程中产生很多额外开销,从而影响系统性能(为缓解此问题,可以减少系统调用的次数,并且让每次系统调用完成尽可能多的工作)
  • 部分硬件会限制底层系统调用一次所能读写的数据块大小。
  标准库函数调用提供缓冲的目的是尽可能少的使用read和write调用的次数,较少系统调用的开销。标准I/O提供三种类型的缓冲:
  • 全缓冲:在填满缓冲区后才进行一次实际I/O操作。当然也可以调用fflush冲洗一个流。当输入输出不涉及交互式设备时,通常采用的是全缓冲,例如磁盘上的文件。
  • 行缓冲:当在输入输出中遇到换行符时,标准I/O执行一次I/O操作。eg.printf.
  • 不带缓冲:标准出错流stderr是不带缓冲的,这就使得错误信息很快被显示出来。
  对于本文中的插图,再补充一个函数:int fileno(FILE*fp);其返回值是标准I/O流关联的文件在下层中的文件描述符。

//标准I/O库实现,read.c

#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *fp;
    char ch;
    
    /*以只读、文本的形式打开本路径下一个名为hello的文件*/
    if((fp=fopen("hello","rt"))==NULL)    
        exit(EXIT_FAILURE);
    ch=fgetc(fp);
    while(ch!=EOF)    //文件尾
    {
        putchar(ch);    
        ch=fgetc(fp);    //读取一个字符
    }
    fclose(fp);

    exit(EXIT_SUCCESS);
}

//-----------------------------------------------------------------------------------------------------------------

//系统调用,read.c


#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFER_SIZE 100

int main(int argc,char **argv)
{
    int i,fd,lenght;
    char buffer[BUFFER_SIZE];
    if(argc<2)
    {
        printf("You haven't input the file name!\n");
        exit(EXIT_FAILURE);
    }
    for(i=1;i<argc;i++)
    {
        if(access(argv[i],F_OK)==-1)    //检查文件是否存在
        {
            printf("%s:there is no such file\n",argv[i]);
            continue;
        }
        /*以读写的方式打开*/
        if((fd=open(argv[i],O_RDWR|O_CREAT,0775))>=0)    
        {
            /*read(...)的返回值是读取到内容的字节数*/
            while(read(fd,buffer,sizeof(buffer)))    
                printf("%s\n",buffer);
            close(fd);
        }
        else
            perror(NULL);
    }
    exit(EXIT_SUCCESS);
}


//---------------------------------------------------------------------------------

//系统调用,write.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char **argv)
{
    int fd;
    int filestateflag;
    if(argc!=3)
    {
        printf("Command is incorrect!\n");
        exit(EXIT_FAILURE);
    }
    /*if((fd=open(argv[1],O_CREAT|O_RDWR,0775))>=0)
    {
        lseek(fd,0,SEEK_END);
        write(fd,argv[2],strlen(argv[2]));
    }*/
    if((fd=open(argv[1],O_APPEND|O_CREAT|O_RDWR,0775))>=0)
    {
        filestateflag = fcntl (fd,F_GETFL,0);
        printf("文件描述状态标志是:%d\n",filestateflag);
        write(fd,argv[2],strlen(argv[2]));
    }    
    else
    {
        perror(NULL);
        exit(EXIT_FAILURE);
    }
    close(fd);
    exit(EXIT_SUCCESS);
}



0 0