c学习笔记 文件输入/ 输出 20210314

与文件进行通信

文本模式和二进制模式

c提供两种访问文件的途径:二进制模式和文本模式。二进制模式下可访问文件的每个字节。
MS-DOS模式下, 用\r\n表示新的一行, Ctrl+z表示文件的结束。

I / O级别

底层I/O(low-level I/O)和标准高级I/O(standard high-level I/O).
c标准只支持标准I/O包, 但是c标准建立了可移植的I/O模型。

标准文件

c程序自动会打开三个文件:标准输入(standard input), 标准输出(standard output), 标准错误输出(standard error output)。
重定向是把其他文件视为标准输入或标准输出。
标准错误输出始终会向屏幕上发送。

标准I/O

标准I/O输入和输出都是缓冲的。极大提高了传输效率。

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
	int ch;
	FILE* fp;
	unsigned long count = 0;
	if (argc != 2)
	{
		printf("Usage: %s filename\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	if ((fp = fopen(argv[1], "r") == NULL))
	{
		printf("Can't open %s\n", argv[1]);
		exit(EXIT_FAILURE);
	}
	while (ch = getc(fp) != EOF)
	{
		putc(ch, stdout);
		count++;
	}
	fclose(fp);
	printf("File %s has %lu characters\n", argv[1], count);
	return 0;
}

检查命令行参数

以上通过检查argc的值检查是否存在命令行参数。
tips:有些系统不识别argv[0]

exit()关闭所有打开的文件并结束程序。
c标准要求0或EXIT_SUCCESS表明成功退出程序。
EXIT_FAILURE表明结束程序失败。
以上的宏和exit()定义在stdlib.h中。
exit()会直接终止程序, return 若在递归程序中, 只会把控制权交给上一级递归。

fopen() 函数

fopen()函数第一个参数是代打开文件的名称(包含该文件名的字符串地址),第二个参数是一个字符串, 表示待打开文件的模式。
“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”————若文件已存在或以独占模式打开文件, 则打开文件失败

UNIX, Linux只有一种文件模式, 带b不带b模式相同。

fopen()返回文件指针(file pointer), 类型是指向FILE的指针。

getc()和putc()函数

getc()与getchar()类似, 其参数为指定的文件的文件指针。
putc()第一个文件是待写入的字符, 第二个参数是文件指针。
stdout是与标准输出相关联的文件指针, 定义在stdio.h中
putc(ch, stdout)与putchar(ch)作用相同。

文件结尾

int ch;
FILE *fp;
fp = fopen("wacky.txt", "r");
while ((ch = getc(fp)) != EOF)
	putchar(ch);

getc()在读到文件结尾时, 将返回特殊值EOF

fclose() 函数

fclose()关闭指定的文件, 必要时刷新缓冲区, 成功返回0, 否则返回EOF

if (fclose(fp) != 0)
	printf("Error");

磁盘已满, 移动硬盘被移除, I/O错误都会导致该函数失败

一个简单的文件压缩程序

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LEN 40
int main(int argc, char* argv[])
{
	FILE* in, * out;
	int ch;
	char name[LEN];//储存输出文件名
	int count = 0;
	if (argc < 2)
	{
		fprintf(stderr, "Usage: %s filename\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	if ((in = fopen(argv[1], "r")) == NULL)
	{
		fprintf(stderr, "I could not open the file]\"%s\"\n", argv[1]);
		exit(EXIT_FAILURE);
	}
	strncpy(name, argv[1], LEN - 5);
	name[LEN - 5] = '\0';
	stcat(name, ".red");
	if ((out = fopen(name, "w") == NULL))
	{
		fprintf(stderr, "Can not creat output file.\n");
		exit(3);
	}
	while ((ch = getc(in)) != EOF)
		if (count++ % 3 == 0)
			putc(ch, out);
	if (fclose(in) != 0 || fclose(out) != 0)
		fprintf(stderr, "Error in closing files\n");
	return 0;
}

fprintf和printf()类似, 但是其第一个参数必须是文件指针, stderr指针把错误信息发送至标准错误输出。
可以同时打开的文件数量有限, 大约为10 - 20个。

文件I/O:fprintf(), fscanf(), fgets(), fputs()

fprintf()和fscanf()函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 41
int main(void)
{
	FILE* fp;
	char words[MAX];

	if ((fp = fopen("wordy", "a+")) == NULL)
	{
		fprintf(stdout, "Can not open \"wordy\" file.\n");
		exit(EXIT_FAILURE);
	}
	puts("Enter words to add to the file; press the # key at the beginning of a line to terminate.");
	while ((fscanf(stdin, "%40s", words) == 1) && (words[0] != '#'))
		fprintf(fp, "%s\n", words);
	puts("File contents:");
	rewind(fp); //指针回到原来位置
	while (fscanf(fp, "%s", words) == 1)
		puts(words);
	puts("done.");
	if (fclose(fp) != 0)
		fprintf(stderr, "Error closing file\n");
	return 0;
} 

a+模式以更新模式打开文件, 在文件末尾添加内容
rewind()让程序回到文件起始的位置, rewind()接受一个文件指针作为参数。
fprint(), fscanf()都把FILE指针作为第一个参数。

fgets() & fputs()函数

fgets()函数第一个参数是表示储存输入位置的地址, 第二个参数是表示待输入字符串大小的整数, 第三个参数是文件指针, 指定待读取文件。

fgets(buf, STLEN, fp);

fgets()读取到第一个换行符的后面, 文件结尾, 或STLEN-1个字符。
fgets()遇到EOF时返回NULL,否则返回它的第一个参数地址。

fputs()接受的第一个参数地址是字符串的地址, 第二个是待写入文件的文件指针。

随机访问: fseek()和ftell()

#include <stdio.h>
#include <stdlib.h>
#define CNTL_Z '\032'
#define SLEN 81
int main(void)
{
	char file[SLEN];
	char ch;
	FILE* fp;
	long count, last;
	puts("Enter the name of the file to be processed:");
	scanf("%80s", file);
	if ((fp = fopen(file, "rb")) == NULL) // 二进制读模式
	{
		printf("reverse can not open %s\n", file);
		exit(EXIT_FAILURE);
	}
	fseek(fp, 0L, SEEK_END);
	last = ftell(fp);
	for (count = 1L; count <= last; count++)
	{
		fseek(fp, -count, SEEK_END);
		ch = getc(fp);
		if (ch != CNTL_Z && ch != '\r')
			putchar(ch);
	}
	putchar('\n');
	fclose(fp);
	return 0;
}

fseek()第一个参数是FILE指针, 第二个参数是偏移量(offset), 必须是long类型的值;第三个参数是模式, 确定起始点,根据ANSI标准, 声明在stdio.h中
SEEK_SET——————文件开始处
SEEK_CUR——————当前位置
SEEK_END——————文件结尾
fseek()正常返回值是1,错误时返回-1;

ftell()函数接受文件指针作为参数, 返回long型指向该文件当前位置距离文件开始处的字节数来确定文件位置。文件第一个字节到文件开始的距离为0。ANSI C规定该定义适用于以二进制模式打开的文件。

二进制模式和文本模式

UNIX只有一种文件格式, 不需要特殊的转换
MS-DOS使用Ctrl+Z标记文本文件的结尾, 二进制模式打开时被看作是一个字符, 实际的文件结尾在该字符之后, 可能紧跟在其后, 也可能用空字符填充, 使文件大小恰好为256的倍数,在DOS环境下不会打印空字符。
MS-DOS用]\r\n表示文本文件换行, 以文本模式打开时将其看作‘\n’, 二进制模式下程序可看见这两个字符。
ANSI C规定, 对于文本模式, ftell返回的值可作为fseek()的第二个参数, 对于MS-DOS, ftell返回值将\r\n看作一个字节计数。

可移植性

ANSI对这些函数降低了要求,
二进制模式下, 部分编译器可能不支持SEED_END模式。
在文本模式下, 只有以下调用可保证其相应的行为:
fseek(file, 0L, SEEK_SET)
fseek(file, 0L, SEEK_CUR)
fseek(file, 0L, SEEK_END)
fseek(file, ftell-pos, SEEK_SET)

fgetpos() & fsetpos() 函数

fseek()和ftell()他们都把文件大小限制在long类型范围内
ANSI C 新赠了处理较大文件的新定位函数:fgetpos()和fsetpos()。其使用fpos_t类型(file position type, 文件定位类型), fpos_t并非基本类型, 而是根据其他类型来定义,fpos_t类型的变量或数据对象可在文件中指定一个非数组型的位置, 没有其他限制

int fgetpos(FILE * restrict stream, fpos_t * restrict pos);

该函数把文件中当前位置距文件开头的字节数放在pos指向的位置上, 成功则返回0, 否则返回非0;

int fsetpos(FILE * stream, const fpos_t * pos);

该函数使用pos指定位置上的fpos类型值来设置文件指针偏移该值后指定的位置(在文件开始处进行偏移), 成功返回0, 否则返回非0, fpos_t的值可通过调用fgetpos()获得。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值