十、定位流

#include <stdio.h>
long ftell(FILE *fp);
//若成功,返回当前文件位置指示;若出错,返回-1L
int fseek(FILE *fp, long offset, int whence);
//若成功,返回0;若出错,返回-1L
void rewind(FILE *fp);

  对于一个二进制文件,whence可以为SEEK_SET/SEEK_CUR/SEEK_END;对于文本文件,whence只能是SEEK_SET,并且offset只能是:0(后退到文件的起始位置)或是对该文件的ftell所返回的值。使用rewind也可以将一个流设置到文件的起始位置。

#include <stdio.h>
off_t ftello(FILE *fp);
int fseeko(FILE *fp, off_t offset, int whence);
//除了偏移量的类型不同,其余同上
#include <stdio.h>
int fgetpos(FILE *restrict fp, fpos_t *restrict pos);
//将文件位置指示器存入pos指向的对象中
int fsetpos(FILE *fp, const fpos_t *pos);

十一、格式化I/O
  此章节太过繁琐,并且意义不大,以后需要使用再过补充。

十二、实现细节

#include <apue.h>
#include <my_err.h> void pr_stdio(const char *, FILE *);
int is_unbuffered(FILE *);
int is_linebuffered(FILE *);
int buffer_size(FILE *); int main(void)
{
FILE *fp; fputs("enter any character\n", stdout);
if(getchar() == EOF)
{
err_sys("getchar error");
} fputs("one line to standard error\n", stderr); pr_stdio("stdin", stdin);
pr_stdio("stdout", stdout);
pr_stdio("stderr", stderr); if((fp == fopen("/etc/passwd", "r")) == NULL)
{
err_sys("fopen error");
}
if(getc(fp) == EOF)
{
err_sys("getc error");
} pr_stdio("/etc/passwd", fp);
exit();
} void pr_stdio(const char *name, FILE *fp)
{
printf("stream = %s, ", name);
if(is_unbuffered(fp))
{
printf("unbuffered");
}
else if(is_linebuffered(fp))
{
printf("linebuffered");
}
else
{
printf("fully buffered");
}
printf(", buffer size = %d\n", buffer_size(fp));
} int is_unbuffered(FILE *fp)
{
return fp->_flags & _IONBF;
}
int is_linebuffered(FILE *fp)
{
return fp->_flags & _IOLBF;
}
int buffer_size(FILE *fp)
{
return fp->_IO_buf_end - fp->_IO_buf_base;
}

5-11 对各个标准I/O流打印缓冲状态信息

十三、临时文件

  ISO C标准I/O库提供了两个函数帮助创建临时文件

#include <stdio.h>
char *tmpnam(char *ptr);
FILE *tmpfile(void);

  tmpnam函数产生一个与现有文件名不同的一个有效路径名字符串,若ptr是NULL,则产生的路径存放在一个静态区,指向该静态区的指针作为函数值返回,后续调用tmpnam时,会重写该静态区;若ptr不是NULL,则认为他应该是长度至少是L_tmpnam的字符数组,用这个名字创建临时文件可能存在问题,因为得到文件名和创建是两个动作,不具有唯一性。tmpfile是直接创建一个临时文件,其操作手法是先调用tmpnam产生一个唯一的路径名,然后创建一个文件,然后立即unlink它。

#include <apue.h>
#include <my_err.h>
int main(void)
{
char name[L_tmpnam], line[MAXLINE];
FILE *fp; printf("%s\n", tmpnam(NULL)); tmpnam(name);
printf("%s\n", name); 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);
exit();
}

5-12 tmpnam和tmpfile函数实例

#include <stdlib.h>
char *mkdtemp(char *template);
//若成功,返回指向目录名的指针;若出错,返回NULL
int mkstemp(char *template);
//若成功,返回文件描述符;若出错,返回-1

  mkdtemp函数创建了一个目录,该目录有一个唯一的名字;mkstemp函数创建了一个文件,该文件有一个唯一的名字,名字是通过template字符串进行选择的,与tempfile不同,mkstemp创建的临时文件不会自动删除,如果希望删除,需要自己手动unlink。

#include <apue.h>
#include <my_err.h>
#include <errno.h> void make_temp(char *template); int main(void)
{
char good_template[] = "/tmp/dirXXXXXX";
char *bad_template = "/tmp/dirXXXXXX"; printf("trying to create first temp file...\n");
make_temp(good_template); printf("trying to create second temp file...\n");
make_temp(bad_template);
exit();
} void make_temp(char *template)
{
int fd;
struct stat buf;
if((fd = mkstemp(template)) < )
{
err_sys("can't create temp file");
} printf("temp name=%s\n", template);
close(fd);
if(stat(template, &buf) < )
{
if(errno == ENOENT)
{
printf("file doesn't exit\n");
}
else
{
printf("stat failed\n");
}
}
else
{
printf("file exists\n");
unlink(template);
}
}

5-13 mkstemp函数的应用

trying to create first temp file...
temp name=/tmp/dirQREuAu
file exists
trying to create second temp file...
Segmentation fault (core dumped)
//第二种情况,指针自身驻留在栈上,编译器把字符串存放在可执行文件的只读段,当mkstemp函数试图修改字符串时,出现了段错误

十四、内存流
  标准I/O库把数据缓存在内存中,因此每次一字符和每次一行的I/O更有效,我们也可以通过调用setbuf或setvbuf函数让I/库使用我们自己的缓冲区在SUSv4中支持了内存流,这就是标准I/O流,虽然仍使用FILE指针进行访问,但其实并没有底层文件,所有的I/O都是通过在缓冲区与贮存之间来回传送字节完成的。有三个函数可用于内存流的创建。

#include <stdio.h>
FILE *fmemopen(void *restrict buf, size_t size, const char *restrict type);

  fmemopen函数允许调用者提供缓冲区用于内存流,buf参数指向缓冲区开始的位置,size参数制订了缓冲区大小的字节数,如果buf参数为空,fmemopen函数分配size字节数的缓冲区,在这种情况下,当流关闭时缓冲区就会被释放。type参数控制如何使用流。其和文件有以下区别:

1.无论何时以追加写方式打开内存流时,当前文件位置设为缓冲区中的第一个null字节,如果缓冲区不存在null字节,则当前位置就设为缓冲区结尾的后一个字节。当流不是以追加写方式打开时,当前位置设置为缓冲区的开始位置。因为追加写模式通过第一个null字节确定数据的尾端,内存流并不适合存储二进制数据。

2.如果buf参数是一个null指针,打开流进行读和写都没有任何意义。

3.任何时候需要增加流缓冲区中数据量以及调用fclose、fflush、fseek、fseeko以及fsetpos时都会在当前位置写入一个null字节

<apue.h>
#include <my_err.h> #define BSZ 48 int main(void)
{
FILE *fp;
char buf[BSZ]; memset(buf, 'a', BSZ-);
buf[BSZ-] = '\0';
buf[BSZ-] = 'X';
if((fp = fmemopen(buf, BSZ, "w+")) == NULL)
{
err_sys("fmemopen failed.");
}
printf("initial buffer contents:%s\n", buf);
fprintf(fp, "hello world");
printf("before flush:%s\n", buf);
fflush(fp);
printf("after flush:%s\n", buf);
printf("len of string in buf = %ld\n", (long) strlen(buf)); memset(buf, 'b', BSZ-);
buf[BSZ-] = '\0';
buf[BSZ-] = 'X';
fprintf(fp, "hello, world");
fseek(fp, , SEEK_SET);
printf("after fseek:%s\n", buf);
printf("len of string in buf = %ld\n", (long) strlen(buf)); memset(buf, 'c', BSZ-);
buf[BSZ-] = '\0';
buf[BSZ-] = 'X';
fprintf(fp, "hello, world");
fclose(fp);
printf("after fclose:%s\n", buf);
printf("len of string in buf = %ld\n", (long) strlen(buf)); return ;
}

5-15 观察内存流的写入操作

#include <stdio.h>
FILE *open_memstram(char **bufp, size_t *size); #include <wchar.h>
FILE *open_wmemstream(wchar_t **bufp, size_t *sizep);

  open_memstream函数创建的流是面向字节的,open_wmemstream是面向宽字节的。他们同fmemopen函数的区别在于:1)创建的流只能写打开;2)不能制定自己的缓冲区,但可以分别bufp和sizep参数访问缓冲区地址和大小;3)关闭流后需要自动释放缓冲区;4)对流添加字节会增加缓冲区大小。

  使用上面必须遵守的规则:缓冲区地址和长度只有在调用fclose或fflush后才有效;这些值只有在下一次流写入或调用fclose前才有效。使用内存流相比临时文件,会有很大的性能提升。

APUE(5)---标准I/O库 (3)的更多相关文章

  1. [05]APUE:标准 I/O 库

    [a] setvbuf / setbuf #include <stdio.h> int setvbuf(FILE *restrict fp, char *restrict buf, int ...

  2. APUE(5)---标准I/O库 (2)

    六.读和写流 一旦打开了流,则可在3种不同类型的非格式化I/O中进行选择,对其进行读.写操作:1)每次一个字符的I/O,一次读或写一个字符,如果刘时代缓冲的,则标准I/O函数处理所有缓冲:2)每次一行 ...

  3. APUE(5)---标准I/O库 (1)

    一.引言 标准I/O库不仅是UNIX,许多i其他操作系统都实现了标准I/O库,所以这个库由ISO C标准说明.标准I/O库处理很多细节,如缓冲区分配,以及优化的块长度执行I/O等.这使得它便于用户使用 ...

  4. APUE 学习笔记(四) 标准I/O库

    1.流与FILE对象 unix I/O系统调用都是针对文件描述符的 标准C的I/O函数都是针对流(文件指针)的,我们使用一个流与一个文件相关联   2.缓冲 标准I/O库提供缓冲的目的就是尽可能减少r ...

  5. APUE之第5章——标准I/O库

    一.知识回顾:文件I/O 文件 I/O 是不带缓冲的 I/O(unbuffered I/O),指每个 read 和 write 都调用内核中的一个系统调用. 对于内核而言,所有打开的文件都通过文件描述 ...

  6. 《UNIX环境高级编程》(APUE) 笔记第五章 - 标准I/O库

    5 - 标准I/O库 Github 地址 1. 标准 I/O 库作用 缓冲区分配 以优化的块长度执行 I/O 等 使用户不必担心如何选择使用正确的块长度 标准 I/O 最终都要调用第三章中的 I/O ...

  7. (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  8. 标准I/O库之临时文件

    ISO C标准I/O库提供了两个函数以帮助创建临时文件. #include <stdio.h> char *tmpnam( char *ptr ); 返回值:指向唯一路径名的指针 FILE ...

  9. 标准I/O库之标准I/O的效率

    程序清单5-1 用getc和putc将标准输入复制到标准输出 #include "apue.h" int main( void ) { int c; while(( c = get ...

随机推荐

  1. win10为什么不能把文件直接拖拽

  2. Game2048

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. 个人总结-----非贪心算法的图的m着色判断及优化问题

    1.问题描述: 对于著名的图的m着色,有两个主要的问题,一个是图的m色判定问题,一个是图的m色优化问题,描述如下. 图的m色判定问题: 给定无向连通图G和m种颜色.用这些颜色为图G的各顶点着色.问是否 ...

  4. 第五章 二叉树(b)树的表示

  5. windows server 2008 远程桌面连接数修改--无限连接

    1.开启远程桌面 我的电脑 |  属性 |  远程设置  |  远程 |  进允许运行使用网络级别身份验证的远程桌面的计算机连接(更安全)(N)

  6. 【校招面试 之 C/C++】第11题 C++ 纯虚函数

    1.纯虚函数 成员函数的形参后面写上=0,则成员函数为纯虚函数. 纯虚函数声明: virtual 函数类型 函数名 (参数表列) = 0: class Person { virtual void Di ...

  7. 关于mybatis缓存配置详解

    一级缓存: 一级缓存是默认的. 测试:在WEB页面同一个查询执行两次从日志里面看同样的sql查询执行两次. 2次sql查询,看似我们使用了同一个sqlSession,但是实际上因为我们的dao继承了S ...

  8. (重要)LRU cache

    [抄题]: [思维问题]: 需要从任何位置访问某数字有没有(重要 ),返回其位置(不重要),所以用hashmap. 需要从任何位置删除,用linkedlist.最终二者结合,用linked hashm ...

  9. 启动apache时,出现httpd: Could not reliably determine the server\'s fully qualified domain name, using 127.0.0.1 for ServerName

    1.通过vi打开apache的配置文件httpd.conf > vi /data/apache/conf/httpd.conf 2.找到#ServerName www.example.com:8 ...

  10. 利用委托机制处理.NET中的异常

    WinForm代码 private void button1_Click(object sender, EventArgs e) { try { Convert.ToInt32("abcd& ...