文件IO

"r"

    只读,文件必须已存在
"w"

    只写,如果文件不存在则创建,如果文件已存在则把文件长度截断(Truncate)为0字节再重新写,也就是替换掉原来的文件内容
"a"

    只能在文件末尾追加数据,如果文件不存在则创建
"r+"

    允许读和写,文件必须已存在
"w+"

    允许读和写,如果文件不存在则创建,如果文件已存在则把文件长度截断为0字节再重新写
"a+"

    允许读和追加数据,如果文件不存在则创建

注意除了r不自动创建文件外,其他都会自动创建文件

在打开一个文件时如果出错,fopen将返回NULL并设置errno,errno稍后介绍。在程序中应该做出错处理,通常这样写:

把文件指针传给fclose可以关闭它所标识的文件,关闭之后该文件指针就无效了,不能再使用了。如果fclose调用出错(比如传给它一个无效的文件指针)则返回EOF并设置errno,errno稍后介绍,EOF在stdio.h中定义:

那为什么printf和scanf不用打开就能对终端设备进行操作呢?因为在程序启动时(在main函数还没开始执行之前)会自动把终端设备打开三次,分别赋给三个FILE *指针stdin、stdout和stderr

比较好的办法是用perror或strerror函数将errno解释成字符串再打印

学线程库时我们会看到,有些函数的错误码并不保存在errno中,而是通过返回值返回,就不能调用perror打印错误原因了,这时strerror就派上了用场:

int fgetc(FILE *stream);
int getchar(void);
返回值:成功返回读到的字节,出错或者读到文件末尾时返回EOF

fputs(strerror(n), stderr);

#include <stdio.h>

int fputc(int c, FILE *stream);
int putchar(int c);
返回值:成功返回写入的字节,出错返回EOF

从终端设备输入时有两种方法表示文件结束,一种方法是在一行的开头输入Ctrl-D(如果不在一行的开头则需要连续输入两次Ctrl-D),另一种方法是利用Shell的Heredoc语法:

$ ./a.out <<END
> hello
> hey
> END
hello
hey

 

#include <stdio.h>

int fseek(FILE *stream, long offset, int whence);
返回值:成功返回0,出错返回-1并设置errno

long ftell(FILE *stream);
返回值:成功返回当前读写位置,出错返回-1并设置errno

void rewind(FILE *stream);

fseek的whence和offset参数共同决定了读写位置移动到何处,whence参数的含义如下:

SEEK_SET

    从文件开头移动offset个字节
SEEK_CUR

    从当前位置移动offset个字节
SEEK_END

    从文件末尾移动offset个字节

#include <stdio.h>

char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);
返回值:成功时s指向哪返回的指针就指向哪,出错或者读到文件末尾时返回NULL

注意,对于fgets来说,'\n'是一个特别的字符,而'\0'并无任何特别之处,如果读到'\0'就当作普通字符读入。如果文件中存在'\0'字符(或者说0x00字节),调用fgets之后就无法判断缓冲区中的'\0'究竟是从文件读上来的字符还是由fgets自动添加的结束符,所以fgets只适合读文本文件而不适合读二进制文件,并且文本文件中的所有字符都应该是可见字符,不能有'\0'。

#include <stdio.h>

int fputs(const char *s, FILE *stream);
int puts(const char *s);
返回值:成功返回一个非负整数,出错返回EOF

缓冲区s中保存的是以'\0'结尾的字符串,fputs将该字符串写入文件stream,但并不写入结尾的'\0'。与fgets不同的是,fputs并不关心的字符串中的'\n'字符,字符串中可以有'\n'也可以没有'\n'。puts将字符串s写到标准输出(不包括结尾的'\0'),然后自动写一个'\n'到标准输出。

posted @ 2013-01-15 16:19  周尚武  阅读(282)  评论(0编辑  收藏  举报