• C5 标准IO库:APUE 笔记


    C5 :标准IO库

       在第三章中,所有IO函数都是围绕文件描述符展开,文件描述符用于后续IO操作。由于文件描述符相关的操作是不带缓冲的IO,需要操作者本人指定缓冲区分配、IO长度等,对设备环境要求一定的了解。

      本章引入文件流概念,IO库将处理很多底层IO细节。

    1 缓冲

      提供缓冲的目的是尽量减少read和write的调用次数。标准IO提供了以下3种缓冲:

    1.1 全缓冲

      在填满标准IO缓冲区后再进行实际IO操作,标准IO函数通常使用malloc获取使用的缓冲区

    1.2 行缓冲

      在输入和输出中遇到换行符时,标准IO才执行IO操作。对于行缓冲有2个限制

    •   标准IO库用来收集每一行的缓冲区长度固定,所以只要是填满了缓冲区,就会进行IO操作
    •   只要是通过标准IO从一个不带缓冲的流或者一个行缓冲的流得到输入数据,那么就会flush行缓冲输出流

    1.3 不带缓冲

      标准库不对字符进行缓冲存储,标准错误流通常是不带缓冲的,这样就可以尽快将信息显示出来

      

      可以使用setbuf函数打开或者关闭缓冲机制,为了带缓冲进行IO,参数buf必须指向一个长度为BUFSIZE的缓冲区,头文件stdio.h。成功返回-,出错返回-1。

    1 /* If BUF is NULL, make STREAM unbuffered.
    2    Else make it use buffer BUF, of size BUFSIZ.  */
    3 extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __THROW;
    4 
    5 /* Make STREAM use buffering mode MODE.
    6    If BUF is not NULL, use N bytes of it for buffering;
    7    else allocate an internal buffer N bytes long.  */
    8 extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf,  int __modes, size_t __n) __THROW;

      setvbuf的mode参数可以精确说明缓冲类型,mode参数实现为:

      _IOFBF  全缓冲,_IOLBF  行缓冲,_IONBF  不带缓冲。

    •   如果指定一个不带缓冲的流,则忽略buf和size参数。
    •   如果指定全缓冲和行缓冲,则buf和size可选择指定一个缓冲区及其长度。
    •   如果流是带缓冲的,而buf是NULL,则标准IO库自动为流分配合适长度的缓冲区,长度由BUFSIZE指定。

    2 流

    2.1 打开、关闭流

      可以使用fopen等函数打开一个IO流,头文件stdio.h。成功返回文件指针,出错返回NULL。

     1 /* Open a file and create a new stream for it.
     2 
     3    This function is a possible cancellation point and therefore not
     4    marked with __THROW.  */
     5 extern FILE *fopen (const char *__restrict __filename,
     6             const char *__restrict __modes) __wur;
     7 /* Open a file, replacing an existing stream with it.
     8 
     9    This function is a possible cancellation point and therefore not
    10    marked with __THROW.  */
    11 extern FILE *freopen (const char *__restrict __filename,
    12               const char *__restrict __modes,
    13               FILE *__restrict __stream) __wur;

      fopen函数打开路径为__filename的文件

      freopen函数在一个指定的流上打开文件。如果该流已经打开,则先关闭该流。如果该流已经定向,则使用freopen清除该定向。

      mode参数指定对该IO流的读写方式,ISO C规定mode参数可以右15种取值。

      使用fclose可以关闭一个打开的流,头文件stdio.h。成功返回0,失败返回-1。

    1 /* Close STREAM.
    2 
    3    This function is a possible cancellation point and therefore not
    4    marked with __THROW.  */
    5 extern int fclose (FILE *__stream);
    6 /* Flush STREAM, or all streams if STREAM is NULL.

    2.2 读、写流

    2.2.1 每次一个字符的IO

      下面函数用于一次读取一个字符,头文件stdio.h。成功返回下一个字符,达到文件尾或者出错,返回EOF(定义在libio.h)。

     1 /* Read a character from STREAM.
     2 
     3    These functions are possible cancellation points and therefore not
     4    marked with __THROW.  */
     5 extern int fgetc (FILE *__stream);
     6 extern int getc (FILE *__stream);
     7 
     8 /* Read a character from stdin.
     9 
    10    This function is a possible cancellation point and therefore not
    11    marked with __THROW.  */
    12 extern int getchar (void);
    13 
    14 #ifndef EOF
    15 # define EOF (-1)
    16 #endif

      前两个函数的区别是,getc可以被实现为宏,而fgetc不能实现为宏?

      getchar等价于geic (stdin)。  

      这三个函数达到文件尾或者出错,都返回EOF。为区别文件尾或者出错,需要调用以下函数进行判断,头文件stdio.h。成功返回非0,失败返回0。可以作为bool型判断。

    1 /* Clear the error and EOF indicators for STREAM.  */
    2 extern void clearerr (FILE *__stream) __THROW;
    3 /* Return the EOF indicator for STREAM.  */
    4 extern int feof (FILE *__stream) __THROW __wur;
    5 /* Return the error indicator for STREAM.  */
    6 extern int ferror (FILE *__stream) __THROW __wur;

      调用clearerr可以清除这两个标志。

      也可以使用ubgetc将字符再写回流缓冲区,头文件stdio.h。成功返回c,失败返回EOF。

    1 /* Push a character back onto the input buffer of STREAM.
    2 
    3    This function is a possible cancellation point and therefore not
    4    marked with __THROW.  */
    5 extern int ungetc (int __c, FILE *__stream);

      对应的写缓冲区函数为:

     1 /* Write a character to STREAM.
     2 
     3    These functions are possible cancellation points and therefore not
     4    marked with __THROW.
     5 
     6    These functions is a possible cancellation point and therefore not
     7    marked with __THROW.  */
     8 extern int fputc (int __c, FILE *__stream);
     9 extern int putc (int __c, FILE *__stream);
    10 
    11 /* Write a character to stdout.
    12 
    13    This function is a possible cancellation point and therefore not
    14    marked with __THROW.  */
    15 extern int putchar (int __c);

    2.2.2 每次一行IO

      下面两个函数每次读写输出一行,头文件stdio.h。成功返回buf,到达文件尾或者出错,返回NULL。

     1 /* Get a newline-terminated string of finite length from STREAM.
     2 
     3    This function is a possible cancellation point and therefore not
     4    marked with __THROW.  */
     5 extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
     6      __wur;
     7 
     8 /* Get a newline-terminated string from stdin, removing the newline.
     9 
    10    This function is impossible to use safely.  It has been officially
    11    removed from ISO C11 and ISO C++14, and we have also removed it
    12    from the _GNU_SOURCE feature list.  It remains available when
    13    explicitly using an old ISO C, Unix, or POSIX standard.
    14 
    15    This function is a possible cancellation point and therefore not
    16    marked with __THROW.  */
    17 extern char *gets (char *__s) __wur __attribute_deprecated__;
    18 
    19 
    20 /* Write a string to STREAM.
    21 
    22    This function is a possible cancellation point and therefore not
    23    marked with __THROW.  */
    24 extern int fputs (const char *__restrict __s, FILE *__restrict __stream);
    25 
    26 /* Write a string, followed by a newline, to stdout.
    27 
    28    This function is a possible cancellation point and therefore not
    29    marked with __THROW.  */
    30 extern int puts (const char *__s);

      注意以下两点:

    •   应当屏蔽使用puts或者gets。这两个函数都是从标准输入或输出读写,但由于无法指定缓冲区长度,将会导致缓冲区溢出错误
    •   程序退出处,显示调用exit(0),将会冲洗任何未写的数据,然后关闭所有打开的流
    •   读写一行都是以NULL为终止,但是缓冲区的NULL不会写入文件

    3 二进制IO

      上一节的流IO无法解决以下问题:当读取的数据是结构化数据(非字符串,可能读取到NULL,0),流IO将会截断。

      为解决该问题,需要引入二进制IO函数fread和fwrite,头文件stdio.h。函数返回读或写的对象数。

     1 /* Read chunks of generic data from STREAM.
     2 
     3    This function is a possible cancellation point and therefore not
     4    marked with __THROW.  */
     5 extern size_t fread (void *__restrict __ptr, size_t __size,
     6              size_t __n, FILE *__restrict __stream) __wur;
     7 /* Write chunks of generic data to STREAM.
     8 
     9    This function is a possible cancellation point and therefore not
    10    marked with __THROW.  */
    11 extern size_t fwrite (const void *__restrict __ptr, size_t __size,
    12               size_t __n, FILE *__restrict __s);

    4 定位流(访问偏移)

      可使用ftell获取当前文件访问偏移量、fseek对文件访问进行偏移、rewind将流设置到起始位置。

     1 /* Seek to a certain position on STREAM.
     2 
     3    This function is a possible cancellation point and therefore not
     4    marked with __THROW.  */
     5 extern int fseek (FILE *__stream, long int __off, int __whence);
     6 /* Return the current position of STREAM.
     7 
     8    This function is a possible cancellation point and therefore not
     9    marked with __THROW.  */
    10 extern long int ftell (FILE *__stream) __wur;
    11 /* Rewind to the beginning of STREAM.
    12 
    13    This function is a possible cancellation point and therefore not
    14    marked with __THROW.  */
    15 extern void rewind (FILE *__stream);

      fseek的第三个参数whence与fseek的参数相同:

      SEEK_SET指定从文件起始位置开始,SEEK_CUR指定从当前位置开始,SEEK_END指定从文件末尾

    5 格式化IO

    5.1 格式化输出

      格式化输出由5个printf函数处理,头文件stdio.h。成功返回字符数,失败返回负值。

     1 /* Write formatted output to stdout.
     2 
     3    This function is a possible cancellation point and therefore not
     4    marked with __THROW.  */
     5 extern int printf (const char *__restrict __format, ...);
     6 
     7 /* Write formatted output to STREAM.
     8 
     9    This function is a possible cancellation point and therefore not
    10    marked with __THROW.  */
    11 extern int fprintf (FILE *__restrict __stream,
    12             const char *__restrict __format, ...);
    13 
    14 extern int dprintf (int __fd, const char *__restrict __fmt, ...)
    15      __attribute__ ((__format__ (__printf__, 2, 3)));
    16 
    17 /* Write formatted output to S.  */
    18 extern int sprintf (char *__restrict __s,
    19             const char *__restrict __format, ...) __THROWNL;
    20 
    21 /* Maximum chars of output to write in MAXLEN.  */
    22 extern int snprintf (char *__restrict __s, size_t __maxlen,
    23              const char *__restrict __format, ...)
    24      __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));

      printf将格式化数据写到标准输出

      fprintf将格式化数据写到指定的流

      dprintf写到指定的文件描述符

      sprintf写到数组S

      snprintf是sprintf的安全版本,指定了缓冲区的长度,防止缓冲区溢出

    5.2 格式化输入

      格式化输入由3个scanf函数处理,头文件stdio.h。成功返回输入的参数,失败或者到达文件末尾,返回EOF。

     1 /* Read formatted input from STREAM.
     2 
     3    This function is a possible cancellation point and therefore not
     4    marked with __THROW.  */
     5 extern int fscanf (FILE *__restrict __stream,
     6            const char *__restrict __format, ...) __wur;
     7 /* Read formatted input from stdin.
     8 
     9    This function is a possible cancellation point and therefore not
    10    marked with __THROW.  */
    11 extern int scanf (const char *__restrict __format, ...) __wur;
    12 /* Read formatted input from S.  */
    13 extern int sscanf (const char *__restrict __s,
    14            const char *__restrict __format, ...) __THROW;

     6 临时文件

      可以使用tmpnam或者tmpfile创建临时二进制文件。头文件stdio.h。

    1 /* Generate a temporary filename.  */
    2 extern char *tmpnam (char *__s) __THROW __wur;
    3 
    4 /* Create a temporary file and open it read/write.
    5 
    6    This function is a possible cancellation point and therefore not
    7    marked with __THROW.  */
    8 extern FILE *tmpfile (void) __wur;

      tmpnam生成一个和现有文件名不同的有效路径字符串,最多调用TMP_MAX次,定义在stdio.h。返回指向唯一路径名的指针。如果输入为NULL,则路径名存放在静态区;如果不是NULL,则应该指向长度为L_tmpnam个字符的数组。

      tmpfile创建一个临时二进制文件,在关闭该文件或者程序结束时将自动删除该文件。可以使用tmpfile创建一个临时文件,然后立即unlink。

    7 内存流

    1 /* Create a new stream that refers to a memory buffer.  */
    2 extern FILE *fmemopen (void *__s, size_t __len, const char *__modes)
    3   __THROW __wur;
    4 
    5 /* Open a stream that writes into a malloc'd buffer that is expanded as
    6    necessary.  *BUFLOC and *SIZELOC are updated with the buffer's location
    7    and the number of characters written on fflush or fclose.  */
    8 extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __THROW __wur;

      

      

  • 相关阅读:
    多线程编程学习笔记——任务并行库(三)
    多线程编程学习笔记——任务并行库(二)
    多线程编程学习笔记——任务并行库(一)
    多线程编程学习笔记——线程池(三)
    多线程编程学习笔记——线程池(二)
    多线程编程学习笔记——线程池(一)
    多线程编程学习笔记——线程同步(三)
    多线程编程学习笔记——线程同步(二)
    多线程编程学习笔记——线程同步(一)
    多线程编程学习笔记-基础(三)
  • 原文地址:https://www.cnblogs.com/hgwang/p/9623970.html
Copyright © 2020-2023  润新知