标准IO和文件IO(1)

标准IO

        接上节

函数接口

(1)fseek函数

1.功能:将文件流中的文件指针从指定的起始位置开始偏移指定的字节数。

2.参数:(目标文件,偏移量,参考点)

  • stream:要移动文件指针的目标文件流对象,注意不支持设备文件,一般用于普通文件。
  • offset:要在文件内偏移的距离,单位为字节。如果值为正数,则向文件末尾偏移;如果值为负数,则向文件开头偏移。
  • whence:偏移的起始位置,由系统定义的三个宏确定,分别是SEEK_SET(文件的开头位置)、SEEK_CUR(文件的当前位置)、SEEK_END(文件的末尾位置)。

3.返回值:成功返回0,失败返回 - 1。

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

int main(int argc, char *argv[])
{
    FILE* fp = fopen("1.txt","w+");
    if(NULL == fp)
    {
        printf("fopen error\n");
        return 1;
    }
    char buf[128]="hello world";
    fputs(buf,fp);
    fseek(fp,0,SEEK_SET);

    bzero(buf,sizeof(buf));
    fgets(buf,sizeof(buf),fp);
    printf("buf is %s\n",buf);

    fclose(fp);
    return 0;
}
(2)ftell函数

1.功能:获取当前文件流指针的具体位置,一般以文件开头到当前指针的字节数为返回值。

2.参数stream为要返回指针距离的文件流对象。

3.返回值:成功获取到的距离长度,单位是字节;失败返回 - 1。

(3)rewind函数

1.功能:将文件指针重新定位到文件的开头,等效于fseek(stream, 0L, SEEK_SET)

2.参数stream为要进行操作的文件流对象。

#include <stdio.h>

int main(int argc, char *argv[])
{
    
    FILE* fp = fopen("1.txt","r");
    if(NULL == fp)
    {
        printf("fopen error");
        return 1;
    }
    char buf[1024]={0};
    fgets(buf,sizeof(buf),fp);
    printf("1 buf is %s\n",buf);
    rewind(fp);
    fgets(buf,sizeof(buf),fp);
    printf("2 buf is %s\n",buf);

    fclose(fp);

    return 0;
}
(4)feof函数:

        标准输入输出库中的一个函数,用于判断文件流指针是否到达文件结尾。

  1. 1.功能:判断当前参数stream的文件流指针是否到达文件结尾。如果到达文件结尾则返回真,否则返回假。注意,该操作一定要在一次IO操作之后判断。
  2. 2.参数stream为要判断结尾的文件流对象,可以是stdin(程序会阻塞等待),如果是普通文件fp则指向文件第一行数据。
  3. 3.返回值:成功到达结尾返回真,否则返回假。

在使用feof函数时,通常与其他文件操作函数结合使用,例如fgetcfread等,用于判断文件是否读取完毕。

缓冲区

1.行缓冲(Line Buffering)

        行缓存是一种缓存机制,主要用于人机交互,如终端(stdout)。

        特点

       (1) 缓存区大小通常为1K。

        (2)刷新条件包括遇到\n刷新、缓存区满刷新、程序结束刷新以及使用fflush刷新(fflush(stdout))。

        (3)行缓存多是关于终端的一些操作,例如在输入输出中,当遇到换行符\n时,会刷新缓存区,将数据输出或读取。

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    // 1 printf("hello\n");
    /* 2
    int i = 0 ;
    for(i = 0 ;i<1025;i++)
    {
        //printf("a");
        fputc('a',stdout);
    }
    while(1)
        sleep(1);
        */

    //3 
    // printf("hello");
    //
    printf("hello");
    fflush(stdout);
    while(1);
    return 0;
}

2.全缓冲(Full Buffering)

        全缓存主要用于文件的读写操作。

        特点

        (1)缓存区大小通常为4K。

        (2)刷新条件包括缓存区满刷新、程序结束刷新以及使用fflush刷新(fflush(fp))。

        (3)对普通文件进行标准IO操作时,建立的缓存一般为全缓存。

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    FILE* fp = fopen("1.txt","w");    
    /*char buf[]="hello";
    fputs(buf,fp);
*/
    /* 4K
    int i = 0 ;
    for(i = 0 ;i<4097;i++)
    {
        fputc('a',fp);
    }
    while(1)
        sleep(1);
        */ 


    char buf[]="hello";
    fputs(buf,fp);
    fflush(fp);

    while(1)
        sleep(1);
    return 0;
}

3.无缓冲(No Buffering)

        不对数据进行缓存,直接刷新。

        特点

        (1)主要用于出错处理信息的输出,如stderr。

        (2)不缓存数据,直接将数据输出或处理。

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    
    fprintf(stderr,"fopen error ");
    while(1)
        sleep(1);
    return 0;
}

        在标准IO中,不同的缓存机制适用于不同的场景,以提高数据处理的效率和性能。例如,行缓存适用于终端交互,能够及时响应用户的输入和输出;全缓存适用于文件读写,能够减少系统调用的次数,提高数据传输的效率;无缓存则适用于需要及时输出错误信息等情况。

文件io


        在操作系统中,为了方便用户使用系统功能,系统对外提供了一组系统函数,称为系统调用,其中包括文件IO。文件IO是一种基于Linux内核的没有缓存的IO机制,主要用于对设备文件和普通文件进行操作。

一、文件IO的特性

  1. 无缓存区:文件IO操作直接对文件进行读写,不依赖于缓存区,这意味着数据的读写更加直接和高效,但也需要用户自己管理数据的缓存。
  2. 文件描述符:文件IO的操作对象是文件描述符,这是一个小的非负整数(通常在0 - 1023之间)。内核为每一个打开的文件分配一个文件描述符,程序可以通过文件描述符来对文件进行操作。
  3. 默认打开的描述符:在程序启动时,操作系统会默认为其打开三个与流对象匹配的描述符:
  • 0 ==> STDIN_FILENO === stdin(标准输入)
  • 1 ==> STDOUT_FILENO == stdout(标准输出)
  • 2 ==> STDERR_FILENO == stderr(标准错误输出)

(1)open函数

1.功能:获得一个文件描述符。

 2.参数:

  • pathname:文件名。
  • flags:
O_RDONLY只读模式
O_WRONLY只写模式
O_RDWR读写模式
O_CREAT创建文件
O_EXCL需要和O_CREAT同时使用,表示新建的文件不能存在,成功,否则open就会失败
O_NOCTTY不是终端设备
O_TRUNC文件内容清空
O_APPEND追加
O_ASYNC异步IO,什么时候IO不确定
O_NONBLOCK非阻塞
  • 返回值:成功返回文件描述符,失败返回 - 1。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    int fd= open("1.txt",O_WRONLY | O_CREAT|O_TRUNC,0666);//truncate
    if(-1 == fd)
    {
        printf("open error\n");
        return 1;
    }
    printf("fd is %d\n",fd);
    return 0;
}

(2)write函数

1.功能:通过文件描述符向文件中写一串数据。

2.参数:

  • fd:文件描述符。
  • buf:要写入文件的字符串的首地址。
  • count:要写入字符的个数。

3.返回值:成功返回实际写入的个数,失败返回 - 1。

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

int main(int argc, char *argv[])
{
    int fd= open("1.txt",O_WRONLY | O_CREAT|O_TRUNC,0666);//truncate
    if(-1 == fd)
    {
        printf("open error\n");
        return 1;
    }
    printf("fd is %d\n",fd);
    char buf[128]="hello,world";
    int wr_ret = write(fd,buf,strlen(buf));
    if(-1 == wr_ret)
    {
        printf("write error\n");
        return 1;
    }
    close(fd);
    return 0;
}

(3)read函数

1.功能:通过文件描述符读取文件中的数据。

2.参数:

  • fd:文件描述符。
  • buf:存放数据空间的首地址。
  • count:要读到数据的个数。

3.返回值:成功返回读到数据的个数,失败返回 - 1,读到文件结尾返回0。

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

int main(int argc, char *argv[])
{
    int fd= open("1.txt",O_RDONLY);//truncate
    if(-1 == fd)
    {
        printf("open error\n");
        return 1;
    }
    printf("fd is %d\n",fd);

    char buf[512]={0};
    int rd_ret = read(fd,buf,sizeof(buf));
    if(rd_ret<=0)
    {
        printf("read eof or error\n");
        return 1;
    }
    printf("ret %d,%s\n",rd_ret,buf);

    close(fd);
    return 0;
}

(4)close函数

1.功能:关闭一个已打开的文件描述符,释放相关资源。

2.参数:需要关闭的文件描述符。

3.返回值:成功返回0,失败返回 - 1。

(5)lseek函数

1.功能:定位文件光标的位置。

2.参数:

  • fd:文件描述符,表示要操作的文件。
  • offset:偏移量,可以是正数(向后偏移)、负数(向前偏移)或零(不偏移)。
  • whence:指定偏移的起始位置,有以下几种取值:
    • SEEK_SET:从文件开头开始计算偏移量。
    • SEEK_CUR:从当前文件光标位置开始计算偏移量。
    • SEEK_END:从文件末尾开始计算偏移量。

3.返回值:成功返回偏移量。失败返回 - 1。

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

int main(int argc, char *argv[])
{
    int fd= open("1.txt",O_WRONLY);//truncate
    if(-1 == fd)
    {
        printf("open error\n");
        return 1;
    }
    printf("fd is %d\n",fd);
    off_t offset = lseek(fd,6, SEEK_SET);
    printf("offset %ld\n",offset);
    write(fd,"china",5);
    close(fd);
    return 0;
}

(6)fileno函数

        功能:返回与文件流stream相关联的文件描述符。
        参数:stream是一个指向文件流的指针。
        返回值:成功时返回文件描述符,出错时返回-1并设置errnoo

#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    //FILE*---> int  fd;
    FILE* fp = fopen("1.txt","r");
    if(NULL == fp)
    {
        printf("fopen error\n");
        return 1;
    }

    char buf[256]={0};
    
    int fd = fileno(fp);
    read(fd, buf,sizeof(buf)-1);
    printf("%s\n",buf);
    fclose(fp);
    return 0;
}

(7)fdopen函数

        功能:将现有的文件描述符fd转换为文件流,并指定文件打开模式mode。
        参数:
                fd:文件描述符。
                mode:文件打开模式(如"r"、“w"、“a”等)。
        返回值:成功时返回FILE *指针,出错时返回NULL并设置errno。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
    //FILE*---> int  fd;
    int fd  = open("1.txt",O_RDONLY);
    if(-1 == fd)
    {
        printf("fopen error\n");
        return 1;
    }

    char buf[256]={0};
    FILE* fp = fdopen(fd,"r");
    if(NULL == fp)
    {
        printf("fdopen error\n");
        return 1;
    }
    fgets(buf,sizeof(buf),fp);
    printf("%s\n",buf);
    fclose(fp);
    return 0;
}

文件IO与标准IO的比较

文件IO

  • 特点:基于Linux内核,没有缓存区,操作对象是文件描述符,直接对文件进行读写。
  • 适用场景:用于底层设备相关的开发。
  • 优势:在某些特定场景下,如对性能要求较高、需要直接操作设备文件等,具有优势。
  • 不足:效率、安全性和移植性相对较差。

标准IO

  • 特点:是对文件IO的封装,使用流(FILE*)进行操作,具有缓存机制(行缓存、全缓存、无缓存)。
  • 适用场景:适用于纯上层开发。
  • 优势:效率和安全性较高,移植性好,使用方便。
  • 不足:对于底层设备的直接操作能力相对较弱。

        总的来说,文件IO更接近底层,适合一些对性能和直接控制有较高要求的场景;标准IO则在大多数上层应用中更为常用,因为它提供了更方便、高效和安全的文件操作方式。在实际开发中,应根据具体需求选择合适的IO方式。

  • 23
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值