1.流
人与计算机的程序进行交互。很多都与I/O操作(输入/输出)有关。显示器,硬盘,内存,键鼠,网口等就是很常见的设备。操作系统负责这些不同设备的通信细节,并向程序员提供一个更为简单和统一的I/O接口。
就C程序而言,所有的I/O操作只是简单地从程序移进或移出字节。这种字节流便称为流(stream )。
绝大多数的流是完全缓冲的,这意味着读取和写入是从一块被称为缓冲区(buffer )的内存区域来回复制数据。
C语言中有三种流对象:标准输入流,标准输出流,标准错误流。
1.1 标准输入流——stdin
stdin (standard input stream),标准输入流是程序默认的数据源 ,大多数系统中,默认数据来源于键盘。 该对象的类型为FILE*(文件类型指针) ,适用于将FILE*作为参数的任何函数如fgets和fscanf。FILE是一个数据结构,用于访问一个流,如文本流和二进制流。 与交互设备无联系时,标准输入流默认完全缓冲。
1.2 标准输出流——stdout
stdout(standard output stream),标准输出流是程序默认输出的目的地 ,默认情况下指向了文本控制台(通常在屏幕上)。 同样,stdout的类型为FILE* ,适用于接受FILE*类型参数的函数,如fputs和fprintf。 与交互设备无联系时,标准输出流默认完全缓冲。
1.3 标准错误流——stderr
strerr(standard error stream),标准错误流是错误消息及诊断警告的默认目的地 ,类型为FILE* ,默认情况下它也被定向到文本控制台。 strerr在启动时不会完全缓冲。
1.4 什么是完全缓冲?
完全缓冲(fully buffered),意味着读出和写入实际上是从一块被称为缓冲区(buffer)的内存区域来回复制数据。 输出流的缓冲区是只有当其被写满时才会被刷新 到设备或文件中。 输入流的缓冲区是当它为空时,通过从设备或文件读取下一块较大的输入,重新填充缓冲区。 将缓冲区一次性写满再进行写入读出 ,相较于逐片传递内存效率更高。 注意 : 当操作系统断定与交互设备没有联系时,才会进行完全缓冲。 我们有时会想让缓冲区的内容直接写入到内存中而非等到缓冲区满时——fflush函数。 fflush迫使缓冲区的数据立即写入,不管它是否已满。
2.I/O函数
这些函数都定义于stdio.h 。标准库函数使我们在C程序中执行文件相关的I/O任务非常方便,
- 当我们想访问一个文件时,就必须为该文件声明一个指针变量,类型为
FILE* 。 - 文件流通过调用
fopen 函数打开,为了打开文件流需要知道文件路径及文件名,以及他们的访问方式(例如,读,写,既读又写)。 - 执行文件的读取或写入。
- 调用
fclose 函数关闭文件流。
标准流的I/O更为简单,因为他们不需要打开和关闭。 输入与输出以三种基本的形式处理数据:单个字符 ,文本行 和二进制数据 。
2.1 fopen — 打开流
FILE * fopen ( const char * filename, const char * mode );
打开在参数filename 中指定的文件,并将其与文件流关联起来。对该文件刘允许的操作,将由mode 参数决定。 mode对应的参数:
“r” | read, 打开文件进行输入操作。文件必须存在 |
---|
“w” | write,为输出操作创建一个空文件。如果同名文件已经存在,则其内容将被丢弃,并将该文件作为一个新的空文件处理。 | “a” | append, 在文件末尾打开文件并输出。输出操作总是将数据写在文件的末尾,将其展开。如果文件不存在,则创建该文件。 | “r+” | read/update,打开一个文件进行更新(用于输入和输出)。文件必须存在。 | “w+” | write/update,创建一个空文件,并打开它进行更新(输入和输出)。如果同名文件已经存在,则其内容将被丢弃,并将该文件作为一个新的空文件处理。 | “a+” | append/update,打开一个文件进行更新(包括输入和输出),将所有的输出操作写入文件的末尾。如果文件不存在,则创建该文件。 |
使用上面的模式说明符,文件将作为文本文件打开。 为了以二进制文件的形式打开文件,模式字符串中必须包含一个“b”字符。这个额外的“b”字符可以被附加在字符串的末尾(这样就形成了以下复合模式:“rb”,“wb”,“ab”,“r+b”,“w+b”,“a+b”)或者插入字母和“+”符号之间的混合模式(“rb+”,“wb+”,“ab+”)。
返回值:成功打开文件,返回一个指向file的指针,否则返回空指针,所以需检查指针是否为空。
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ("myfile.txt","r");
if (pFile==NULL)
{
perror("fopen:");
}
else
{
printf("打开文件成功\n");
}
fclose(pFile);
pFile=NULL;
return 0;
}
如果打开工程文件失败,则会返回NULL:
2.2 fclose — 关闭流
int fclose ( FILE * stream );
关闭与流关联的文件,并解关联。 与流关联的所有内部缓冲区都被解除关联并刷新:写入任何未写入输出缓冲区的内容,丢弃任何未读输入缓冲区的内容。
如果流成功关闭,则返回一个零值。 如果失败,则返回EOF。
关闭文件后需使原本指向文件的FILE指针重新指向NULL,以防止其称为野指针。
file* pf=fopen(...);
....
if(fclose(pf)!=0)
{
perror("fclose");
exit(EXIT_FAILURE);
}
....
2.3字符的I/O
2.3.1输入字符 函数:
int fgetc(FILE* stream);
int getc(FILE* stream);
int getchar(void);
需要操作的流作为参数传递给getc和fgetc,但getchar始终从标准输入(stdin)读取。每个函数从流中读取下一个字符,并把它作为函数的返回值返回,然后将内部文件位置指示器推进到下一个字符 。如果流中不存在更多的字符,函数就返回常量值EOF,并设置流的文件结束指示符(feof)。
举例
int main()
{
FILE* pf = fopen("myfile.txt", "r+");
if (pf == NULL)
{
perror("fopen");
exit(EXIT_FAILURE);
}
int c;
do
{
c = fgetc(pf);
printf("%c ", c);
} while (c != EOF);
fclose(pf);
pf = NULL;
return 0;
}
预先设置好文件 得到结果:
2.3.2输出字符 函数:
int fputc(int character,FILE* stream);
int putc(int character,FILE* stream);
int putchar(int character);
将字符写入流并推进位置指示器。字符被写入流的内部位置指示器所指示的位置,然后该指示器将自动前进1。 举例
int main ()
{
FILE * pFile;
char c;
pFile = fopen ("alphabet.txt","w");
if (pFile!=NULL) {
for (c = 'A' ; c <= 'Z' ; c++)
fputc ( c , pFile );
fclose (pFile);
}
return 0;
}
w的打开方式,将新建一个文件,并把字母表写入其中。 每写入一个字母,内部位置指示器就会前进1. 注意 : fgetc和fputc都是真正的函数,但getc、putc、getchar和putchar都是通过#define指令定义的宏。
2.4 行的I/O
|