精华内容
下载资源
问答
  • 标准IO函数

    2020-09-01 18:33:06
    标准IO中所有函数都是属于标准C库中的接口,所以标准IO函数都是属于man手册中第3手册。 2、如何使用标准IO访问文件? 1)访问文件? -> fopen() -> man 3 fopen 函数功能: stream open functions 头文件:...

    一、标准IO。
    1、标准IO有什么特点?
    系统IO专门用于访问硬件设备的,标准IO专门用于访问普通文件。
    标准IO中所有函数都是属于标准C库中的接口,所以标准IO的函数都是属于man手册中第3手册。

    2、如何使用标准IO访问文件?
    1)访问文件?  ->  fopen()  -> man 3 fopen
    函数功能: stream open functions
    头文件:#include <stdio.h>
    原型:
        FILE *fopen(const char *path, const char *mode);
        
    参数:
        path:需要打开的那个文件的路径  (绝对路径/相对路径)
        mode:操作权限  -> 字符串  例如:"r"

     r      Open text file for reading.  The stream is positioned at the beginning of the file.
        //以只读的方式来打开文件,文件的定位在最开头的。
        O_RDONLY

     r+     Open for reading and writing.  The stream is positioned at the beginning of the file.
        //以可读可写的方式来打开文件,文件的定位在最开头的。
        O_RDWR

     w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.
        //以只写的方式打开文件,如果文件不存在就创建该文件,如果文件存在,则清空文件的内容,文件的定位在最开头的。
        O_WRONLY|O_CREAT|O_TRUNC

     w+     Open for reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The  stream  is  positioned at the beginning of the file.
        //以可读可写的方式来打开文件,如果文件不存在就创建该文件,如果文件存在,则清空文件的内容,文件的定位在最开头的。
        O_RDWR|O_CREAT|O_TRUNC

     a      Open  for  appending  (writing at end of file).  The file is created if it does not exist.  The stream is positioned at the end of the file.
        //以只写追加的方式打开文件,写的话就在文件末尾开始写,文件不存在就会创建,文件的定位在末尾。
        O_WRONLY|O_APPEND

     a+     Open for reading and appending (writing at end of file).  The file is created if it does not exist.  The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.
        //以可读可写和追加的方式打开文件,写的话就在文件末尾开始写,文件不存在就会创建,如果读,就从文件开头读,如果写,就从文件末尾开始写。
        O_RDWR|O_CREAT|O_APPEND

    返回值:
        成功:文件流指针  FILE *
        失败:NULL

    2)关闭文件。  -> fclose()  -> man 3 fclose
    函数功能: fclose - close a stream
    头文件:#include <stdio.h>
    原型:
        int fclose(FILE *stream);

    参数:
        stream: 需要关闭的那个文件的文件指针

    返回值:
        成功:0
        失败:EOF

    #define EOF -1

      练习1: 测试一下fopen()打开一个文件后,会不会占用一个文件描述符?
      练习2: 打开一个文件,测试fopen第二个参数,并关闭文件。

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

    int main(int argc,char *argv[])
    {
        FILE *fp = NULL;
        fp = fopen("./test.txt","w");
        if(fp == NULL)
            printf("fopen error!\n");  -> 3
        
        int fd = open("./kk.txt",O_RDONLY);
        printf("fd = %d\n",fd);
        
        fclose(fp);
    }

    二、关于默认打开的三个文件的文件指针。
    头文件:/usr/include/unistd.h

    /* Standard file descriptors.  */
    #define    STDIN_FILENO    0    标准输入的文件描述符
    #define    STDOUT_FILENO    1    标准输出的文件描述符
    #define    STDERR_FILENO    2    标准出错的文件描述符

    头文件:/usr/include/stdio.h
    typedef struct _IO_FILE FILE;

    /* Standard streams.  */
    extern struct _IO_FILE *stdin;        标准输入的文件流指针  
    extern struct _IO_FILE *stdout;        标准输出的文件流指针
    extern struct _IO_FILE *stderr;        标准出错的文件流指针

    /* C89/C99 say they're macros.  Make them happy.  */
    #define stdin stdin
    #define stdout stdout
    #define stderr stderr

    总结:
            文件描述符            文件指针
    标准输入        STDIN_FILENO           stdin
    标准输出        STDOUT_FILENO          stdout
    标准出错        STDERR_FILENO          stderr

    三、关于标准IO的读写操作。
    1、如何读取文件?  -> fread()  -> man 3 fread
    头文件:#include <stdio.h>
    原型:
           size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

    参数:
        ptr: 数据缓冲区
        size: 每一个块的字节数。 
        nmemb: 想读取的块数。   
        stream:需要读取的文件的文件描述符。

    返回值:
        成功:成功读取到的块数
        失败:小于想读取的块数/0

    文件总字节数:        30                             24                                 28
           想读3块,每一块10个字节  -> 3     想读3块,每一块10个字节 -> 2         想读3块,每一块10个字节  -> 2
           想读2块,每一块15个字节  -> 2     想读2块,每一块15个字节 -> 1         想读2块,每一块15个字节  -> 1
           想读5块,每一块10个字节  -> 3     想读5块,每一块10个字节 -> 2         想读5块,每一块10个字节  -> 2
                                               想读5块,每一块6个字节    -> 4
      结论: 一定要读取到那一块数据的字节等于你想读取的块的字节时,才能算一块。
        如果读取到那一块数据的字节小于你想读取的块的字节时,不能够算一块。


    文本内容:helloworldhelloworldhelloworld
    30个字节。
    char buf[100] = {0};
    fread(buf,10,3,fp);//3  //buf: helloworldhelloworldhelloworld

    文本内容:helloworldhelloworldhell
    24个字节。
    char buf[100] = {0};
    fread(buf,10,3,fp);//2  //buf:helloworldhelloworldhell

    文本内容:helloworldhelloworldhell
    24个字节。
    char buf[100] = {0};
    fread(buf,30,1,fp);//0  //buf: helloworldhelloworldhell  -> 虽然返回值为0,但是也能读取到东西。

    文本内容:helloworldhelloworldhellowor
    28个字节。
    char buf[100] = {0};
    fread(buf,10,3,fp);//2  //buf: helloworldhelloworldhellowor

      结论:不能直接通过返回值来判断读取到的内容是多少的。
            fread(buf,10,3,fp);

    返回值为2  -> 不能说就读取到了20个字节,我们只能判断出了读到20个/20个以上,但是一定是30个以下。        
              但是读到20几个?我们不知道。

    2、写入文件?  -> fwrite()  -> man 3 fwrite
    头文件:#include <stdio.h>
    原型:
        size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

        ptr: 需要写入到文件中的内容。
        size:  每一个块的字节数。
        nmemb: 想写入的块数。 
        stream: 目标文件的文件指针。

    返回值:
        成功:写入的块数。 
        失败:小于想写入的块数/0。 

    char buf[] = "helloworldhelloworldhelloworld"   -> 30

    fwrite(buf,10,3,fp);
    返回值:3
    文件内容:helloworldhelloworldhelloworld

    fwrite(buf,15,2,fp);
    返回值:2
    文件内容:helloworldhelloworldhelloworld

    fwrite(buf,10,5,fp);
    返回值:5
    文件内容:helloworldhelloworldhelloworld + 1个空格 + 19个乱码

    fwrite(buf,6,5,fp);
    返回值:5
    文件内容:helloworldhelloworldhelloworld

    fwrite(buf,5,5,fp);
    返回值:5
    文件内容:helloworldhelloworldhello

    fwrite(buf,20,1,fp);
    返回值:1
    文件内容:helloworldhelloworld

    fwrite(buf,40,1,fp);
    返回值:1
    文件内容:helloworldhelloworldhelloworld + 1个空格 + 9个乱码

      结论: fwrite()你想写多少块,返回值就是多少,如果内容不够,就乱码来凑。

       练习3:  先读,再读,是继续读,还是重新读?
                先写,再写,是继续写,还是重新写?
            先读,再写,是继续写,还是重新写?
            先写,再读,是继续读,还是重新读?   -> 四个都是继续。

    #include <stdio.h>

    int main(int argc,char *argv[])
    {
        //1. 访问文件
        FILE *fp = NULL;
        fp = fopen("./ggy.txt","r+"); //helloworld
        if(fp == NULL)
            printf("fopen error!\n");
        
        //2. 先读一些内容
        char buf[10] = {0};
        fread(buf,3,2,fp);  
        printf("buf = %s\n",buf); //buf:hellow
        
        //3. 再写一些内容进去
        fwrite("appletree",4,2,fp); //文件的内容: hellowappletre
        
        //4. 关闭文件
        fclose(fp);
        
        return 0;
    }

       结论: 标准IO读写操作会影响到文件的偏移量,而且打开文件时,默认文件偏移量在文件的开头。

    四、关于重新定位的问题。
    1、重新定位文件流指针。  -> fseek()  -> man 3 fseek
    功能: reposition a stream
        //重新定位流指针

    头文件:#include <stdio.h>
    原型:
        int fseek(FILE *stream, long offset,  int whence);

    参数:
        stream: 需要发生偏移的文件指针。
        offset: 需要偏移的字节数。
        whence: SEEK_SET  -> 相对于文件的开头。
             SEEK_CUR  -> 相对于当前的位置。
             SEEK_END  -> 相对于文件的末尾。

    返回值:
        成功:0
        失败:-1

    2、获取当前位置距离开头的偏移量。 -> ftell()  -> man 3 ftell
    头文件:#include <stdio.h>
    原型:
        long ftell(FILE *stream);

    参数:
        stream:文件流指针。

    返回值:
        成功:距离文件开头的偏移量
        失败:-1

    3、重置文件指针。  -> rewind() -> man 3 rewind
    头文件:#include <stdio.h>
    原型:
          void rewind(FILE *stream);


    参数:
        stream:文件流指针。

    返回值:无

       例子: 写一个代码,试试以上几个函数。

    #include <stdio.h>
    #include <strings.h>

    int main(int argc,char *argv[])                                                          
    {
        FILE *fp = fopen("./ggy2.txt","w+");
        if(fp == NULL)
            printf("fopen error!\n");
        
        char buf[10] = "appletree";
        fwrite(buf,4,2,fp);
        
        rewind(fp);
        
        char buf2[20] = {0};
        int n = fread(buf2,10,2,fp);
        printf("n = %d\n",n);  //0
        printf("buf2 = %s\n",buf2); //appletre
        
        char *p = "helloworld";
        n = fwrite(p,5,2,fp);
        printf("n = %d\n",n);//2
        
        long a = ftell(fp);
        printf("a = %ld\n",a);//18
        
        fseek(fp,-13,SEEK_CUR);
        
        bzero(buf2,sizeof(buf2));
        fread(buf2,4,2,fp);
        printf("buf2 = %s\n",buf2);//trehello
                    //文件内容:appletrehelloworld
        fclose(fp);
        
        return 0;
    }

    练习4: 假设当前目录下有一个1.txt的文件,里面有一些内容,但是我们不知道里面有多少个字节,要求大家写一个程序copy.c
           当执行:./copy 1.txt 2.txt 时。2.txt会自动创建,2.txt的内容与1.txt完全一致。使用标准IO来完成。

    #include <stdio.h>

    int main(int argc,char *argv[]) //./p4 1.txt 2.txt
    {
        FILE *fp1 = fopen(argv[1],"r");
        FILE *fp2 = fopen(argv[2],"w");
        
        char buf[10] = {0};
        int n;
        long a,b;
        while(1)
        {
            a = ftell(fp1);
            
            n = fread(buf,5,2,fp1);
            if(n == 2)
            {
                fwrite(buf,10,1,fp2);
            }
            
            if(n < 2) //最后一次
            {
                b = ftell(fp1);
                fwrite(buf,b-a,1,fp2);
                break;
            }
        }
        
        fclose(fp1);
        fclose(fp2);
        
        return 0;    
    }

    五、printf()输出问题。
    printf()输出对象默认是标准输出,标准输出是有缓冲区的,也就是说这些缓冲区需要特定的条件才会输出数据。
    printf()是一个行缓冲函数,就是只要在缓冲区遇到'\n',就会把'\n'之前的数据全部输出。

    例子1:
    int main(int argc,char*argv[])
    {
        printf("helloworld");
        printf("yueqian");
        return 0;
    }
    结果:helloworldyueqian
    结论:当程序退出时,会刷新标准输出缓冲区。

    例子2:
    int main(int argc,char*argv[])
    {
        printf("helloworld");
        printf("yueqian");
        while(1);
        return 0;
    }
    结果:不会输出任何内容。
    结论:当程序不退出时,是不会刷新标准输出缓冲区。

    例子3:
    int main(int argc,char*argv[])
    {
        printf("helloworld");      
        printf("yueqian\n");
        printf("appletree");
        while(1);
        return 0;
    }
    结果:helloworldyueqian
    结论:当遇到'\n'时,就会将之前的数据全部输出。

    例子4:
    int main(int argc,char*argv[])
    {
        while(1)
        {
            printf("hello");
            usleep(100000); //0.1S 
        }
        return 0;
    }
    结果:等到缓冲区满了,就会将缓冲区的数据全部输出。
    结论:printf()如果缓冲区满了,即使程序没有结束,也没有'\n',也是会全部输出的。

    例子5:
    int main(int argc,char*argv[])
    {
        int x;
        printf("helloworld"); 
        scanf("%d",&x);     
        while(1);
        return 0;
    }
    结果:输出helloworld。
    结论:键盘stdin会刷新标准输出。

    例子6:主动刷新缓冲区。  -> fflush()  -> man 3 fflush
    功能: flush a stream
        //刷新一个流

    头文件:#include <stdio.h>
    原型:
        int fflush(FILE *stream);

    参数:
        stream: 需要刷新的流指针。  -> stdout

    返回值:
        成功:0
        失败:EOF

    #include <stdio.h>
    #include <unistd.h>
    int main(int argc,char*argv[])
    {
        printf("helloworld"); 
        printf("yueqian");
        fflush(stdout);
        while(1);
        return 0;
    }
    结果:helloworldyueqian
    结论:fflush会主动刷新缓冲区。

    例子7:修改printf()的输出对象为标准出错,因为标准出错是没有缓冲区的,所以往标准出错上写入到数据,有什么数据就会输出什么。
    修改输出对象:fprintf()  -> man 3 fprintf

    头文件:#include<stdio.h>
    原型:
        int fprintf(FILE *stream, const char *format, ...);

    参数:
        stream: 输出对象    -> stderr
        format: 输出内容

      printf("hello");  等价于 fprintf(stdout,"hello");  -> 将hello这个字符串放在标准输出的缓冲区上。
                   fprintf(stderr,"hello");  -> 将hello这个字符串放在标准出错上。

    #include <stdio.h>
    #include <unistd.h>
    int main(int argc,char*argv[])
    {
        fprintf(stderr,"helloworld"); 
        while(1);
        return 0;
    }
    结果:输出helloworld
    结论:标准出错没有缓冲区。

    六、标准IO函数。
    sprintf()  getchar()  getc()  fgetc()  putchar()  putc()  fputc()  puts()  gets()  fgets()

    1、sprintf()  -> 保存一个字符串,拼接字符串。  -> man 3 sprintf
    头文件:#include <stdio.h>
    原型:
        int sprintf(char *str, const char *format, ...);

    参数:
        str:数据缓冲区
        format:字符串格式

    返回值:
        字符串总字节数。

    int a = 10;
    printf("a = %d\n",a);  -> 将a的值放置到%d的位置,然后将"a = 10\n"这句话输出到标准输出上。

    int a = 10;
    char buf[30] = {0};
    sprintf(buf,"a = %d\n",a);  -> 将a的值放置到%d的位置,然后将"a = 10\n"这句话保存到数组buf中。
                    -> buf必须足够大去接受字符串。
        

    1、完成昨晚的第3题。
    2、修改项目中系统IO为标准IO。
    3、把项目中错误信息改成刷颜色。

    4、究竟小孩退出登录时,要不要强制保存小孩的数据。
       家长  -> 修改了小孩的年龄,密码之类  -> 需要保存到文件中。

    展开全文
  • Linux系统标准IO函数

    2020-03-18 22:41:42
    标准IO函数 使用底层系统调用open/read/write等对文件进行操作效率非常低,原因主要有两个: 使用系统调用会影响系统的性能。与函数调用相比,系统调用的开销较大,因为在执行系统调用时,Linux必须从运行用户代码...

    标准IO函数

    使用底层系统调用open/read/write等对文件进行操作效率非常低,原因主要有两个:

    • 使用系统调用会影响系统的性能。与函数调用相比,系统调用的开销较大,因为在执行系统调用时,Linux必须从运行用户代码切换到内核代码,然后再返回用户代码。而减少这种开销的一个好方法是,在程序中尽量减少系统调用的次数,并且让每次系统调用完成尽可能多的工作。
    • 硬件会限制对底层系统调用一次所能读写的数据块。

    为了个设备和磁盘文件提供更高层的接口,Linux发行版提供一个标准函数库。标准IO库及其头文件stdio.h为底层IO系统调用提供了一个通用的接口。这个库现在已经成了ANSI标准C的一部分,库函数主要包括fopen/fread/fwrite/printf/scanf/fprintf/fscanf等库函数。

    fopen函数

    #include<stdio.h>
    FILE *fopen(const char *filename, const char *mode);
    

    fopen库函数打开由filename参数指定的文件,并把它与一个文件流关联起来。fopen成功时返回一个非空的FILE*指针,失败时返回NULL值。

    参数说明:

    • filename:指定打开的文件名
    • mode:指定打开文件的方式,可能是一下字符串中的一种:
    字符串 说明
    “r"或"rb” 以只读方式打开
    “w"或"wb” 以写方式打开,并把文件原有内容删除
    “a"或"ab” 以写方式打开,新内容追加在文件尾
    "r+"或"rb+“或"r+b” 以读写方式打开
    "w+"或"wb+“或"w+b” 以读写方式打开,并文件原有内容删除
    "a+"或"ab+“或"a+b” 以读写方式打开,新内容最佳在文件尾

    字母b表示文件是一个二进制文件,但是Linux并不区分文本文件和二进制文件,而是把所有文件都看作为二进制文件。

    Linux系统可用的文件流数量和文件描述符一样都是有限制的,实际的限制由头文件stdio.h中定义的POPEN_MAX定义,它的值至少为8,Linux系统通常为16。

    fread函数

    #include<stdio.h>
    
    size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
    

    fread函数用于从一个文件流里读取数据。返回值是成功读到数据缓冲区里的记录个数(而不是字节数)。

    参数说明:

    • ptr:指定数据缓冲区
    • size:指定每个元素的大小,以字节为单位
    • nitems:指定要读取元素的个数,每个元素的大小为size字节
    • stream:指定要读取的文件流指针

    fwrite函数

    #include<stdio.h>
    
    size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
    

    fwrite函数用于从指定的数据缓冲区里取出数据记录,并把它们写到输入流中。返回值是成功写入的记录个数。

    参数说明:

    • ptr:指定数据缓冲区
    • size:指定每个元素的大小,以字节为单位
    • nitems:指定要写入元素的个数,每个元素的大小为size字节
    • stream:指定要写入的文件流指针

    fclose函数

    #include<stdio.h>
    
    int fclose(FILE *stream);
    

    fclose函数用于关闭一个文件流,并使所有尚未写出的数据都写出。

    因为stdio库会对数据进行缓冲,所以使用fclose是很重要的。如果程序需要确保数据已经全部写出,就应该调用fclose函数。当程序正常结束时,会自动对所有还打开的文件流调用fclose函数。

    fflush函数

    #include<stdio.h>
    
    int fflush(FILE *stream);
    

    fflush函数把文件流里的所有未写出的数据立即写出。调用fclose函数隐含执行了一次flush操作,所以不必在调用fclose之前调用fflush。

    fseek函数

    #include<stdio.h>
    
    int fseek(FILE *stream, long int offset, int whence);
    

    fseek函数在文件流里为下一次读写操作指定位置。返回值是一个整数:0表示成功,-1表示失败并设置errno指出错误。

    参数说明:

    • stream:指定文件流指针
    • offset:指定偏移量
    • whence:指定偏移量的用法,可选下列值之一:
    说明
    SEEK_SET offset是一个绝对位置
    SEEK_CUR offset是相当于当前位置的一个相对位置
    SEEK_END offset是相对于文件尾的一个相对位置

    fgetc、getc和getchar函数

    #include<stdio.h>
    
    int fgetc(FILE *stream);
    int getc(FILE *stream);
    int getchar();
    

    fgetc函数从文件流里取出下一个字节并把它作为一个字符返回。当它到达文件尾或出现错误时返回EOF。

    getc函数作用同fgetc一样。

    getchar函数的作用相当于getc(stdin),从标准输入里读取下一个字符。

    fputc、putc和putchar函数

    #include<stdio.h>
    
    int fputs(int c, FILE *stream);
    int putc(int c, FILE *stream);
    int putchar(int c);
    

    fputc函数把一个字符写到输出文件流中。返回值是写入的值,失败返回EOF。

    putc函数作用同fputc函数.

    putchar函数相当于putc(c,stdout),将字符c写到标准输出文件流中。

    fgets和gets函数

    #include<stdio.h>
    
    char *fgets(char *s, int n, FILE *stream);
    char *gets(char *s);
    

    fgets函数把读到的字符写到s指向的字符串里,直到遇到换行符或者已经读取n-1个字符或者遇到文件尾。它会把遇到的换行符也传递到接收字符串里,再加上一个表示结尾的空字符尾0。

    fgets成功完成时返回一个指向字符串s的指针,如果文件流已经到达文件尾,fgets会设置这个文件流的EOF标识并返回一个空指针。如果出现读错误,fgets返回一个空指针并设置errno。

    gets函数从标准输入读取数据并丢弃遇到的换行符,并在接收字符串尾部加上一个null字节。警告:gets对传输字符的个数并没有限制,所以它可能会溢出自己的传输缓冲区,所以应该避免使用gets函数。

    许多安全问题都可以追溯到程序中使用了可能造成各种缓冲区溢出的函数,gets就是一个这样的函数。

    printf、fprintf和sprintf函数

    #include<stdio.h>
    
    int printf(const char *format, ...);
    int sprintf(const *s, const char *format, ...);
    int fprintf(FILE *stream, const char *format, ...);
    

    printf函数将输出送到标准输出流。
    sprintf函数把输出加上一个结尾空字符送到字符串s中。
    fprintf函数把输出输送到指定的文件流中。

    format为输出格式类型,通常有以下几种常用的转换控制符:

    转换控制符 说明
    %d,%i 以十进制格式输出一个整数
    %o,%x 以八进制或十六进制格式输出一个整数
    %c 输出一个字符
    %s 输出一个字符串
    %f 输出一个单精度浮点数
    %e 以科学计数法输出一个双精度浮点数
    %g 以通用格式输出一个双精度浮点数

    scanf、fscanf和sscanf函数

    #include<stdio.h>
    
    int scanf(const char *format, ...);
    int fscanf(FILE *stream, const char *format, ...);
    int sscanf(const char *s,const char *format,. ...);
    

    scanf系列函数使用一个格式字符串来控制输入数据的转化。
    scanf函数从标准输入流中读入数据。fscanf函数从指定的文件流中读入数据。sscanf函数则从指定的字符串中读入数据。

    format为输入格式类型,通常有以下几种常用的转换控制符:

    转换控制符 说明
    %d 读取一个十进制整数
    %o,%x 读取一个八进制或十六进制的整数
    %c 读取一个字符
    %s 读取一个字符串
    %f 读取一个单精度浮点数
    %e 读取一个科学计数法表示的双精度浮点数
    %g 读取一个通用格式表示双精度浮点数
    %[] 读取一个字符集合
    %% 读取一个%字符

    值得一提的是,使用%c空字符从输入中读取一个字符,它不会跳过起始的空白字符。

    关于scanf的安全性问题,由于scanf系列函数可以接受任意的键盘输入,如果输入的长度超出了应用给定的缓冲区,就会覆盖其他数据区,造成缓冲区溢出,而溢出的数据可能覆盖其他内存空间的数据,造成程序崩溃。


    参考文献:《Linux程序设计(第4版)》

    展开全文
  • linux中系统io函数(read,write)与标准io函数(fgets,fputs)速度和效率的对比 起因:在学习《tcpip网络编程》第15章io缓冲部分时,对两种io的速度比较感兴趣,书中没有给出明确的测试用例,网上搜索了一下,发现有些...

    起因:在学习《tcpip网络编程》第15章io缓冲部分时,对两种io的速度比较感兴趣,书中没有给出明确的测试用例,网上搜索了一下,发现有些结论竟然说速度相差不大,于是自己进行测试

    策略:使用不同函数读取test.txt,复制到cpy.txt中
    测试文件:test.txt , 大小17M
    结论:系统io函数总用时17s,c标准函数总用时0.4s,后者效率远远超出

    系统io函数(read,write)

    syscpy.c

    #include <stdio.h>
    #include <fcntl.h>
    #define BUF_SIZE 3
    
    int main(int argc, char *argv[])
    {
    	int fd1, fd2, len;
    	char buf[BUF_SIZE];
    
    	fd1=open("test.txt", O_RDONLY);
    	fd2=open("cpy.txt", O_WRONLY|O_CREAT|O_TRUNC);
    
    	while((len=read(fd1, buf, sizeof(buf)))>0)
    		write(fd2, buf, len);
    
    	close(fd1);
    	close(fd2);
    	return 0;
    }
    

    c标准io函数(fgets,fputs)

    stdcpy.c

    #include <stdio.h>
    #define BUF_SIZE 3
    
    int main(int argc, char *argv[])
    {
    	FILE * fp1;
    	FILE * fp2;
    	char buf[BUF_SIZE];
    	
    	fp1=fopen("test.txt", "r");
    	fp2=fopen("cpy.txt", "w");
    
    	while(fgets(buf, BUF_SIZE, fp1)!=NULL)
    		fputs(buf, fp2); 
    
    	fclose(fp1);
    	fclose(fp2);
    	return 0;
    }
    

    系统io函数
    在这里插入图片描述
    标准io函数
    在这里插入图片描述

    展开全文
  • 标准IO函数:软件级别的操作函数 fopen:打开一个文件 #include &amp;lt;stdio.h&amp;gt; FILE *fopen(const char *path, const char *mode); path:打开文件的路径 mode:打开文件的权限 r:只读...
    标准IO函数:软件级别的操作函数
    

    fopen:打开一个文件

        #include <stdio.h>
        FILE *fopen(const char *path, const char *mode);
    
        path:打开文件的路径
        mode:打开文件的权限
            r:只读,文件定位在开头
            r+:读写,文件定位在开头
            w:只写,并且会将内部内容清空,文件定位在开头,文件不存在会被创建
            w+:读写,文件不存在会被创建,文件定位在开头
            a:只写,文件定位在末尾,如果不存在会被创建
            a+:读写,文件定位在末尾,如果不存在会被创建
    
        返回值:
            成功返回一个文件指针
            失败返回NULL
    

    fclose:关闭文件指针

        #include <stdio.h>
        int fclose(FILE *stream);
    
        stream:文件操作指针
    
        返回值:
        成功返回0
        失败返回EOF
    

    fread:读取文件内容

        size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
        ptr:读取的内容存放到哪里
        size:每一块数据的大小
        nmemb:多少块数据
        stream:文件指针
    
    返回值:
        函数正常返回读取到的块数,以下这几种情况将会返回不等于块数的返回值:
            A、文件读到末尾了,剩余的内容不够读满那么多块,那他就会返回读到多少块整块,而后面不满一块的内容,虽然已经读了,但是他不会记录在总数中
                调用feof判断文件是否到达末尾
            B、文件读取出错了
                调用ferror判断文件是否出错
    

    fwrite:写入数据到文件中

    size_t fwrite(const void *ptr, size_t size, size_t nmemb,
                     FILE *stream);
        ptr:写入的内容
        size:每一块数据的大小
        nmemb:多少块数据
        stream:文件指针
    
    返回值:
        函数正常返回写入的块数,以下这一种情况将会返回不等于块数的返回值:
            文件写入出错了
            调用ferror判断文件是否出错
    

    ferror函数:判断文件出错

        int ferror(FILE *stream);
        判断文件操作是否出错
        如果出错返回真(非0值)
    

    feof:判断文件操作是否到达文件末尾

    int feof(FILE *stream);
    判断文件操作是否到达文件末尾
    如果到达则返回真
    

    clearerr:

    void clearerr(FILE *stream);
    清楚文件操作中的错误标志,以不至于每次调用ferror都判断出错
    

    ftell:测量当前位置到文件开头的距离

        long ftell(FILE *stream);
    

    fseek:偏移文件的操作位置

        int fseek(FILE *stream, long offset, int whence);
        stream:文件指针
        offset:偏移多少个字节
        whence:从哪里开始偏移
        SEEK_SET, SEEK_CUR, or SEEK_END
    
        返回值:
            成功返回0
            失败返回-1
    

    rewind:将操作位置直接定位到文件开头

        void rewind(FILE *stream);
    
        fdopen:通过文件描述符调用标准IO的借口,返回一个文件指针
        FILE *fdopen(int fd, const char *mode);
        fd:文件描述符
        mode:打开的权限(同fopen)
        注意:这个权限应该跟open打开的权限一致
    
        返回值:
        返回一个操作指针
    

    freopen:重新一个文件打开

        FILE *freopen(const char *path, const char *mode, FILE *stream);
        用于重新用新的权限打开一个一样的文件
        path:文件路径
        mode:文件的权限
        stream:文件之前打开的文件指针
    
        返回值:
        返回一个新的文件操作指针
        失败返回NULL
    

    fileno:获取对应的文件指针的文件描述符

        int fileno(FILE *stream);
    

    fflush:清除缓冲区

    fprintf:

        打印指定内容到文件指针当中
        int fprintf(FILE *stream, const char *format, ...);
        stream:你想要打印的文件指针
        format:数据格式,之后这段内容会打印到stream当中
        ...:变参函数的参数
    

    dprintf:打印指定内容到文件描述符当中

        int dprintf(int fd, const char *format, ...);
        fd:你想要答应的文件描述符
        format:数据格式,之后这段内容会打印到stream当中
        ...:变参函数的参数
    
        #include <stdarg.h>
    
            int vprintf(const char *format, va_list ap);
            int vfprintf(FILE *stream, const char *format, va_list ap);
            int vdprintf(int fd, const char *format, va_list ap);
            int vsprintf(char *str, const char *format, va_list ap);
            int vsnprintf(char *str, size_t size, const char *format, va_list ap);
    
    
            以上函数跟printf等函数用法跟意义一致,只是他们用配合变参函数的参数列表来引用
            va_list:这个是变参函数的数据指针(链表头)
    

    fscanf:从指定的文件指针中获取格式化数据

        int fscanf(FILE *stream, const char *format, ...);
        stream:文件指针
        format:指定格式
        ...:存入的参数(地址)
    

    int fgetc(FILE *stream);

        从steam中获取一个字符
    

    char *fgets(char *s, int size, FILE *stream);

        从stream专用获取一行(如果一行超过size的大小,则size这么大)存放到s中
    

    int getc(FILE *stream);

        从steam中获取一个字符(宏函数,最好用fgetc)
    

    int getchar(void);

        从键盘获取一个字符
    

    int ungetc(int c, FILE *stream);

        反向往stream中扔入一个字符到steam的缓冲区中
    

    int fputc(int c, FILE *stream);

        往steam中写入一个字符c
    

    int fputs(const char *s, FILE *stream);

        往stream中写入s数据
    

    int putc(int c, FILE *stream);

        往steam中写入一个字符c
    

    int putchar(int c);

        往屏幕输出一个字符c
    

    int puts(const char *s);

        往屏幕输出s数据
    

    课后习题

    目录索引(将目录里面的所有文件打印出来)
    
    展开全文
  • 本章内容1. 位操作(位运算)1.1 什么是位操作,有什么意义1.2 能不能对浮点数进行“位操作”1.3 &、|、^与 && || !的区别1.4 &(位与)1.5 |(位或)1.6 ~(位取反)1.7 ^(异或)1.8... c语言的标准IO函数2...
  • 标准IO函数学习

    2019-09-19 06:36:34
    1.fopen/fclose 1.1fopen #include <stdio.h> FILE *fopen(const char *path, const char *mode); 返回值:成功返回文件指针,出错返回NULL并设置errno path:文件路径名...
  • UNIX高级环境编程(7)标准IO函数库 - 二进制文件IO,流定位,创建临时文件和内存流 1 二进制IO(Binary IO) 在前一篇我们了解了逐字符读写和逐行读写函数。 如果我们在读写二进制文件,希望以此...
  • 标准IO函数库隐藏了buffer大小和分配的细节,使得我们可以不用关心预分配的内存大小是否正确的问题。 虽然这使得这个函数库很容易用,但是如果我们对函数的原理不熟悉的话,也容易遇到很多问题。 1 流和FILE实体...
  • #include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; long length = 0; if((fp = fopen("test.txt", "r")) == NULL) { perror("fopen"); return -1; } ... printf(
  • linux标准IO函数

    2013-01-09 09:39:37
    标准I/O函数库:  C标准库提供了文件的标准 I/O 函数库,相比前述的系统调用,主要差别是实现了跨平台的用户态缓冲的解决方案。标准I/O库使 用简单,与系统调用I/O相似,也包括打开、读写、关闭这些操作,主要的...
  • 我的文件权限是够的 都是 644 源代码如下 #include #include #define N 64 int main(int argc, const char *argv[]) { int n; char buf[N]; FILE *fps,*fpd; if(NULL == (fps = fopen(argv[1],"r")))...这是为啥
  • 文章目录文件输入 / 输出本章内容与文件进行通信文件是什么文本模式和二进制模式I/O的级别标准文件标准I/O检查命令行参数fopen()函数getc()和putc()函数文件结尾fclose()函数指向标准文件的指针一个简单的文件压缩...
  • 标准IO函数以及基本知识点总结

    千次阅读 2014-08-10 11:20:26
    标准IO知识,零基础入门,入了门的还可以回顾下哦,本文语言简洁深刻不乏幽默风趣,适合各大牛菜鸟,嘿嘿,,,
  • 在定义头文件时避免重复定义 ...extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。   最好不要在头文件中定义变量 关键字----ex...
  • 1、mstdio.h头文件 #ifndef __MSTDIO_H__ #define __MSTDIO_H__ #include <sys/types.h> #define MEOF -1 enum mode{READ, WRITE, APPEND}; typedef struct { int _fd;... //文件打开
  • c中的标准io函数

    2012-10-06 15:44:00
    函数有个缺陷:不检查目标数组是否能够容纳输入,很不安全,事实上,这正是蠕虫病毒的原理。 对于重要的编程,应该使用 fgets() 而不是 gets() 。     特征 参数 返回值 fputs ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,582
精华内容 1,032
关键字:

标准io函数