标准I/O
C语言标准I/O有许多专门的函数简化了处理不同I/O的问题。例如,printf()
把不同形式的数据转换成与终端相适应的字符串输出。第二,输入和输出都是缓冲的也就是说,一次转移一大块信息而不是一字节信息(通常至少512字节)。
一个简单例子
下面是用C语言标准I/O读取文件和统计文件中的字符数的代码:
#include <stdio.h>
#include <stdlib.h> // 提供 exit()的原型
int main(){
// 读取文件时,存储每个字符的地方
int ch;
// “文件指针”
FILE *fp;
unsigned long count = 0;
char fName[] = "C:\\Users\\MSI-\\Desktop\\test.txt";
if ((fp = fopen(fName, "r")) == NULL)
{
printf("Can't open %s\n", fName);
exit(EXIT_FAILURE);
}
while ((ch = getc(fp)) != EOF)
{
//与 putchar(ch); 相同
putc(ch, stdout);
count++;
}
fclose(fp);
printf("\nFile %s has %lu characters\n", fName, count);
return 0;
}
文件内容:
运行结果:
fopen()函数
该程序使用fopen()
函数打开文件。该函数声明在stdio.h
中。它的第1个参数是待打开文件的名称,更确切地说是一个包含该文件名的字符串地址。第2个参数是一个字符串,指定待打开文件的模式。
模式字符串 | 含义 |
---|---|
"r" | 以读模式打开文件 |
"w" | 以写模式打开文件,把现有文件的长度截为0,如果文件不存在,则创建一个新文件 |
"a" | 以写模式打开文件,在现有文件末尾添加内容,如果文件不存在,则创建一个新文件 |
"r+" | 以更新模式打开文件(即可以读写文件) |
"w+" | 以更新模式打开文件(即,读和写),如果文件存在,则将其长度截为0;如果文件不存在,则创建一个新文件 |
"a+" | 以更新模式打开文件(即,读和写),在现有文件的末尾添加内容,如果文件不存在则创建一个新文件;可以读整个文件,但是只能从末尾添加内容 |
"rb"、"wb"、"ab"、"rb+"、"r+b"、"wb+"、"w+b"、"ab+"、"a+b" | 与上一个模式类似,但是以二进制模式而不是文本模式打开文件 |
"wx"、"wbx"、"w+x"、"wb+x"、"w+bx" | (C11)类似非x模式,但是如果文件已存在或以独占模式打开文件,则打开文件失败 |
像UNIX和Linux这样只有一种文件类型的系统,带b
字母的模式和不带b
字母的模式相同。
新的C11新增了带x
字母的写模式,与以前的写模式相比具有更多特性。第一,如果以传统的一种写模式打开一个现有文件,fopen()
会把该文件的长度截为0,这样就丢失了该文件的内容。但是使用带x
字母的写模式,即使fopen()
操作失败,原文件的内容也不会被删除。第二,如果环境允许,x
模式的独占特性使得其他程序或线程无法访问正在被打开的文件。
如果使用任何一种
"w"
模式(不带x
字母)打开一个现有文件,该文件的内容会被删除,以便程序在一个空白文件中开始操作。然而,如果使用带x
字母的任何一种模式,将无法打开一个现有文件。
程序成功打开文件后,fopen()
将返回文件指针,其他I/O函数可以使用这个指针指定该文件。文件指针(该例中是fp
)的类型是指向FILE
的指针,FILE
是一个定义在stdio.h
中的派生类型。
文件指针fp
并不指向实际的文件,它指向一个包含文件信息的数据对象,其中包含操作文件的I/O函数所用的缓冲区信息。因为标准库中的I/O函数使用缓冲区,所以它们不仅要知道缓冲区的位置,还要知道缓冲区被填充的程度以及操作哪一个文件。标准I/O函数根据这些信息在必要时决定再次填充或清空缓冲区。fp指向的数据对象包含了这些信息(该数据对象是一个结构体)。
getc()和putc()函数
getc()
和putc()
函数与getChar()
和putChar()
函数类似。所不同的是,要告诉getc()
和putc()
函数使用哪一个文件,下面这条语句的意思是“从标准输入中获取一个字符”:
ch = getchar();
然而,下面这条语句的意思是“从fp
指定的文件中获取一个字符”:
ch = getc(fp);
与此类似,下面语句的意思是“把字符ch
放入FILE
指针fpout
指定的文件中”:
putc(ch, fpout);
在putc()
函数的参数列表中,第1个参数是待写入的字符,第2个参数是文件指针。
上面程序中把stdout
作为putc()
的第2个参数,putc(ch, stdout)
与putchar(ch)
的作用相同。
实际上,putchar()
函数一般通过putc()
来定义。与此类似,getchar()
也通过使用标准输入的getc()
来定义。
文件结尾
从文件中读取数据的程序在读到文件结尾时要停止。如何告诉程序已经读到文件结尾?如果getc()
函数在读取一个字符时发现是文件结尾,它将返回一个特殊值EOF
。所以C程序只有在读到超过文件末尾时才会发现文件的结尾(一些其他语言用一个特殊的函数在读取之前测试文件结尾,C语言不同)。
为了避免读到空文件,应该使用入口条件循环(不是do while)进行文件输入。鉴于getc()
(和其他C输入函数)的设计,程序应该在进入循环体之前先尝试读取。如下面设计所示:
// 设计范例 #1
int ch; // 用int类型的变量存储EOF
FILE * fp;
fp = fopen("wacky.txt", "r");
ch = getc(fp); // 获取初始输入
while (ch != EOF)
{
putchar(ch); // 处理输入
ch = getc(fp); // 获取下一个输入
}
以上代码可简化为:
// 设计范例 #2
int ch;
FILE * fp;
fp = fopen("wacky.txt", "r");
while (( ch = getc(fp)) != EOF)
{
putchar(ch); //处理输入
}
fclose()函数
fclose(fp)
函数关闭fp
指定的文件,必要时刷新缓冲区。对于较正式的程序,应该检查是否成功关闭文件。如果成功关闭,fclose()
函数返回0,否则返回EOF
:
if (fclose(fp) != 0)
printf("Error in closing file %s\n", argv[1]);
如果磁盘已满、移动硬盘被移除或出现I/O错误,都会导致调用fclose()
函数失败。
指向标准文件的指针
stdio.h头文件把3个文件指针与3个标准文件相关联,C程序会自动打开这3个标准文件。如下表所示:
标准文件 | 文件指针 | 通常使用的设备 |
---|---|---|
标准输入 | stdin | 键盘 |
标准输出 | stdout | 显示器 |
标准错误 | stderr | 显示器 |
这些文件指针都是指向FILE
的指针,所以它们可用作标准I/O函数的参数,如fclose(fp)
中的fp
。
实现拷贝文件的程序
下面程序实现拷贝文件:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE * in, *out;
int ch;
char inName[] = "C:\\Users\\MSI-\\Desktop\\test.txt";
char outName[] = "C:\\Users\\MSI-\\Desktop\\test2.txt";
if((in = fopen(inName, "r")) == NULL) {
printf("Can't open %s\n", inName);
exit(1);
}
if((out = fopen(outName, "w")) == NULL) {
printf("Can't create file %s\n", outName);
exit(1);
}
while ((ch = getc(in)) != EOF) {
putc(ch, out);
}
if(fclose(in) != 0 || fclose(out) != 0) {
fprintf(stderr, "error");
}
return 0;
}
标签:fp,文件,ch,函数,getc,模式,C语言,标准,IO
From: https://www.cnblogs.com/wwjj4811/p/16650305.html