Chapter5-标准I/O库(补充)-「APUE读书笔记」

  • 实现

每个标准I/O流都有一个相关联的文件描述符,可以用fileno函数来获取。

#include

int    fileno(FILE*  fp);           //POSIX支持的扩展,函数dup和fcntl需要此函数

one line to standard error
stream = stdin, line buffered, buffer size = 1024
stream = stdout, line buffered, buffer size = 1024
stream = stderr, unbuffered, buffer size = 1
stream = /etc/passwd, fully buffered, buffer size = 4096
由范例可看出流连接到终端时是行缓冲

而当流定向到文件时

stream = stdin, fully buffered, buffer size = 4096
stream = stdout, fully buffered, buffer size = 4096
stream = stderr, unbuffered, buffer size = 1
stream = /etc/passwd, fully buffered, buffer size = 4096
流变为了全缓冲,标准错误仍然不带缓冲

  • 临时文件

#include

char*    tmpnam(char*  ptr);          //返回路径

FILE*    tmpfile();                           //返回文件指针,错误返回NULL

tmpnam产生的路径放在静态区,若需多次使用该路径应该保存路径副本,重复调用tmpnam会覆盖静态区。

tmp创建临时二进制文件(wb+),在关闭文件或程序终止时自动删除。

char name[L_tmpnam], line[MAXLINE];
FILE* fp;
 
printf("%s\n", tmpnam(NULL));
tmpnam(name);
printf("%s\n", name);
FILE* fp2;
if((fp2 = fopen(name, "r+")) == NULL)
  err_sys("fopen error");
if((fp = tmpfile()) == NULL)
  err_sys("tmpfile error");
fputs("one line of output\n", fp);
rewind(fp);
if(fgets(line, sizeof(line), fp) == NULL)
  err_sys("fgets error");
fputs(line, stdout);  
输出
/tmp/fileC9o7x4
/tmp/fileojVsqW
fopen error: No such file or directory

可以看到tmpnam产生的路径名已经不能再打开,因为使用tmpnam后会立即unlink它(解除链接而不删除内容)。

同时在编译时有如下提示

/tmp/cc57tA4p.o:在函数‘main’中:
5.13.cpp:(.text+0x21): 警告: the use of `tmpnam' is dangerous, better use `mkstemp'
事实上XSI扩展部分定义了另外两个函数mkdtemp和mkstemp

char*    mkdtemp(char*  template);       //成功返回目录路径,出错返回NULL

int    mkstemp(char*  template);            //成功返回文件描述符,出错返回-1

template是后6位设置为XXXXXX的路径名,函数将占位符替换成随机字符来构建文件名或目录名。

mkstemp返回文件描述符并以读写方式打开,而且不同于tempfile,此临时文件并不会自动删除。

tmpnam和tempnam在返回路径名和创建文件间有时间差,在这之间该路径名可能被占用,所以推荐使用tmpfile和mkstemp。

  • 内存流

创建内存流的函数

#include

FILE*    fmemopen(void*  restrict  buf,  size_t  size,  const  char*  restrict  type);

成功返回流指针,错误返回NULL。buf为空时,分配size字节的缓冲,这样在关闭流时缓冲区被释放。

以追加方式打开内存流时,当前文件位置设为缓冲区的第一个null字节,若没有则设为缓冲区结尾的后一个字节。如果不是以追加方式打开时,当前位置设为缓冲区开始位置。

增加流缓冲区中数据量以及调用fclose,fflush,fseek,fseeko,fsetpos都会在当前位置写入一个null字节。

还有两个函数是

#include

FILE*  open_memstream(char**  bufp,  size_t*  sizep);                     //面向字节

#include

FILE*  open_wmemstream(wchar_t**  bufp,  size_t*  sizep);            //面向宽字节

不同于fmemopen,

  • 这两个只能以写打开
  • 不能指定自己的缓冲区,但可以通过bufp和sizep来访问缓冲区的地址和大小
  • 关闭流后需手动释放缓冲区
  • 对流添加字节会增加缓冲区大小

缓冲区调整后需调用fclose或fflush才能生效,并且只在下次写入或fclose前才有效,因为缓冲区的增长可能重新分配内存。内存流适合创建字符串,把流作为参数用于临时文件的函数,可以大大提高性能。


你可能感兴趣的:(C++/C,读书笔记)