文件操作

1、概述

文件有磁盘文件和设备文件;前者指一组数据的有序集合,通过存储在外部介质(磁盘)上,使用时才调用内存;

后者指在操作系统中把每一个与主机相连的输出、输入设备看做是一个文件,把它们的输入、输出等同于对磁盘文件的读写。

磁盘文件分类

计算机的存储在物理上是二进制的,所以物理上所有的磁盘文件本质都是一样的,以字节为单位进行顺序存储;

从用户或者操作系统使用的角度(逻辑上)把文件分为:
文本文件:基于字符编码的文件;二进制文件:基于值编码的文件

文本文件和二进制文件

1)文本文件:

基于字符编码,常用编码:ASCII、UNICODE;一般使用文本编辑器直接打开;

数5678以ASCII存储形式为:00110101  00110110  00110111  00111000

2)二进制文件

基于值编码,根据具体应用,指定某个值是什么意思;把内存中的数值按其在内存中的存储形式原样输出到磁盘上,

数5678以二进制形式存储:00010110  00101110

2、文件的打开与关闭

文件指针

指C语言中,用一个指针变量指向一个文件。

typedef struct
{
    short level;         //缓冲区满或者空的程度
    unsigned flags;      //文件状态标志
    char fd;             //文件描述符
    unsigned char hold;  //如无缓冲区不读字符
    short bsize;         //缓冲区的大小
    unsigned char *buffer; //数据缓冲区的位置
    unsigned ar;           //指针,当前的指向
    unsigned istemp;      //临时文件,指示器
    short token;          //用于有效性的检查
}FILE;

FILE是系统typedef定义出来有关信息的一种结构体类型,结构中含有文件名、文件状态和文件当前位置等信息。

声明FILE结构体类型信息包含在头文件"stdio.h"中,一般设置一个指向FILE类型变量的指针变量,然后通过它来应用这些FILE类型变量,通过文件指针就可对它所指的文件进行各种操作;

C语言中,有三个特殊文件指针有系统默认打开,用户无需定义即可直接使用:
stdin:标准输入,默认以当前终端(键盘),使用scanf、getchar函数;

stdout:标准输出,默认以当前终端(屏幕),使用printf、puts函数;

stderr:标准出错,默认以当前终端(屏幕),使用perror函数

例子

#include<stdio.h>

int main()
{
	printf("aaaaaaaaaaaa\n");
	//fclose(stdout);//关闭标准输出文件指针//stdout和屏幕关联,关闭后屏幕无法打印 
	printf("bbbbbbbbbbbbb\n"); 
	
	//打印库函数调用失败原因
	perror("mike");//函数括号内只能写字符串 
	fclose(stderr);//关闭关联打印库函数调用失败原因
	perror("jiang");
	 
	 int a;
	 printf("请输入a:");
	// fclose(stdin);//关闭和键盘关联 
	 scanf("%d",&a);
	 printf("a = %d\n",a);
	return 0;
 } 

文件打开

#include <stdio.h>

FILE * fopen(const char * filename, const char * mode);

功能:打开文件

参数:

filename:需要打开的文件名,根据需要加上路径

mode:打开文件的模式设置

返回值:

成功:文件指针

失败:NULL
第一个参数的几种形式:

FILE *fp_passwd = NULL;

//相对路径,打开当前目录passwd 文件:源文件所在的目录
FILE *fp_passed = fopen("passwd","r");
//打开当前目录(test)下passwd.txt文件
fp_passwd = fopen("./test/passwd.txt", "r");
//打开当前目录上一级目录(相对当前目录)passwd.txt文件
fp_passwd = fopen("../passwd.txt","r");
//绝对路径:打开C盘test目录下一个passwd.txt文件
fp_passwd = fopen("c:/test/passwd.txt", "r");

第二个参数的几种形式(打开文件的方式):

打开模式

含义

r或rb

以只读方式打开一个文本文件(不创建文件,若文件不存在则报错

w或wb

以写方式打开文件(如果文件存在则清空文件文件不存在则创建一个文件)

a或ab

追加方式打开文件,在末尾添加内容,文件不存在创建文件

r+或rb+

以可读、可写的方式打开文件(不创建新文件)

r+或rb+

以可读、可写的方式打开文件(不创建新文件)

w+或wb+

以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)

a+或ab+

以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件

Notes:

b是二进制模式,b只是在Windows有效,在Linux用r和rb的结果一样

Unix和Linux下所有文件的文本文件行都是\n结尾,而Windows所有文本文件行都是\r\n结尾

在Windows下,以文本方式打开文件,不加b:

      当读取文件时,系统会将所有的“\r\n”转换为“\n”;

      当写入文件时,系统会将所有的\n转换为\r\n;

      以二进制方式打开文件,则读写都不会进行这样的转换

在Unix/Linux平台下,文本和二进制模式没有区别,“\r\n”作为两个字符原样输入输出

#include<stdio.h>

int main(void){
	FILE * fp=NULL;
	//"\\"这样路劲形式,只能在Windows下使用
	//'/'这样路劲形式,Windows和Linux下都可用,建议使用这样
	//路劲可以相对路径,也可绝对路径 
	fp = fopen("./test","w");
	if(fp==NULL)  //返回空,说明打开失败
	{
		//perror:标准出错打印函数,能打印调用库函数出错原因
		perror("open");
		return -1; 
	} 
	return 0;

}

文件关闭

任何文件在使用之后应该关闭:

打开文件会占用内存资源,总是打开不关闭,会消耗很多内存;

一个进程同时打开的文件数是有限制的,超过最大同时打开文件数,再次调用fopen打开文件会失败

 没有明确的调用fclose关闭打开文件,程序在退出时候,操作系统会统一关闭;

#include <stdio.h>

int fclose(FILE * stream);
/*
功能:关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。
参数:
stream:文件指针
返回值:
成功:0
失败:-1*/

//演示
FILE * fp = NULL;
fp=fopen("ass.txt", "r");
fclose(fp);
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
//#include<fcnt1.h>//err:LINUX?

int main()
{
	printf("aaaaaaaaaaaa\n");
	fclose(stdout);//关闭标准输出文件指针//stdout和屏幕关联,关闭后屏幕无法打印 
//	close(1);  
	//stdout = fopen("F:\DEV_Cdbug\01.txt","w");//err:赋值数据类型不一致?
	 
	 //int fd = fopen("01.txt",O_WRONLY,0777);
	 //int fd = fopen("01.txt","w");
	 FILE* fd = fopen("01.txt","w");//ok
	 //dup(1); //lINUx

    printf("fd = %d\n",fd); 
	printf("bbbbbbbbbbbbb\n"); 
	printf("ccccccccccccc\n"); 
	printf("dddddddddddddd\n"); 
	printf("dddddddddddddd\n"); 
	printf("dddddddddddddd\n"); 
	fclose(fd);
	fd = NULL; 
	
	return 0;
 } 
/*printf:aaaaaaaaaaaa
01.txt
fd = -1924138448
bbbbbbbbbbbbb
ccccccccccccc
dddddddddddddd
dddddddddddddd
dddddddddddddd
*/

文件的顺序读写

按照字符读写文件fgetc、fputc

注:字符串数组使用:char *p[]={"1hello\n","2hello\n","3hello\n"};

1)写文件

#include <stdio.h>

int fputc(int ch, FILE * stream);

功能:将ch转换为unsigned char后写入stream指定的文件中

参数:

ch:需要写入文件的字符

stream:文件指针

返回值:

成功:成功写入文件的字符

2失败:返回-1

例子:fputc(),写字符ch到给定输出流stream,在内部,在写入前将字符转换为 unsigned char

#include<stdio.h>
#include<string.h>

int main()
{
	//定义文件指针fp
	FILE* fp =NULL;
	fp = fopen("01.txt","w");
    char buf[]="a test for fputc";
    int i=0;
    int len = strlen(buf);
    for(i=0;i<len;i++){
        //向文件fp写入字符buf[i]
        int ch = fputc(buf[i],fp);
        printf("ch=%c\n",ch);
    }
	
	return 0;
 } 

2)文件结尾

在C语言中,EOF表示文件结束符(end of file)。在while循环中以EOF作为文件结束标志,前提必须是文本文件;

文本文件中,数据都是以字符的ASCII代码值形式存放,ASCII代码值范围:0-127,不可能出现-1,故用EOF作为文件结束标志;

#define EOF -1

当数据以二进制形式放到文件中时,就有-1值的出现,不能采用EOF作为二进制文件的结束标志,ANSI C 提供一个feof函数,用来判断文件是否结束。feof函数既可用来判断二进制文件,也可判断文本文件。

#include <stdio.h>

int feof(FILE * stream);

功能:检测是否读取到了文件结尾判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)

参数:

stream:文件指针

返回值:

非0值:已经到文件结尾

0:没有到文件结尾//???

例子

#include<stdio.h>
#include<string.h>

//1、如果时文本文件,可以通过-1(EOF)判断文件是否结尾
//2\如果是二进制文件,不能以-1判断文件结尾
//3、feof()判断文件是否结尾,任何文件都能判断 
void write_file()
{
		//1、打开文件
	FILE *fp = NULL; 	
	//一些方式打开文件,果文件不存在,自动新建,
	fp = fopen("03.txt","w");
	if(fp == NULL)
	{
		perror("write_file fopen");
		return ;
	}
	//2、写文件fputc(),一次只能写一个字符
	fputc('a',fp);
	fputc('b',fp);
	fputc('c',fp);
	fputc(-1,fp);
	fputc('d',fp);
	fputc(-1,fp);
	fputc('e',fp);// 
	 
	//3、关闭文件 
    fclose(fp);
	fp = NULL; 
}
void read_file()
{
	//1、打开文件
	FILE *fp = fopen("03.txt","r");
	if(fp == NULL)
	{
		perror("read_file fopen");
		return ;
	}
	//2、读文件fgetc(),每次只读一个字符
	char ch;
	
	while(1)
	{
		ch = fgetc(fp);
		//if(ch == -1)//文本文件以”-1“结尾,”-1“为隐藏。 
	//	if(ch == EOF)//EOF为内部定义的宏,值为-1; 
	     if(feof(fp)) //如果文件结尾,返回真 
		{
			break;
		}
		//printf("ch = %c\n",ch);
		printf("ch = %d\n",ch);
	 } 
     
	//3、关闭文件 
    fclose(fp);
	fp = NULL; 
	
}

int main()
{
	//1、写文件 
	write_file();
	//2、读文件 
	read_file();
		
	return 0;
 } 
/*
ch = a
ch = b
ch = c
ch = 
ch = d
ch = 
ch = e
--------------------------------
*/

3)读文件

#include <stdio.h>

int fgetc(FILE * stream);

功能:从stream指定的文件中读取一个字符

参数:

stream:文件指针

返回值:

成功:返回读取到的字符

失败:-1

//两种结尾方式:文本文件:EOF;二进制文件and文本文件:feof
char ch;
#if 0
while ((ch = fgetc(fp)) != EOF)
{
	printf("%c", ch);
}
printf("\n");
#endif

while (!feof(fp)) //文件没有结束,则执行循环
{
	ch = fgetc(fp);
	printf("%c", ch);
}
printf("\n");

按照行读写文件fgets、fputs

1)写文件

#include <stdio.h>

int fputs(const char * str, FILE * stream);

功能:将str所指定的字符串写入到stream指定的文件字符串结束符 '\0'  不写入文件。

参数:

str:字符串

stream:文件指针

返回值:

成功:0

失败:-1

#include<stdio.h>
#include<string.h>

int main()
{
	//
	FILE* fp =NULL;
	fp = fopen("01.txt","w");
	char *buf[] = { "123456\n", "bbbbbbbbbb\n", "ccccccccccc\n" };//使用一个字符数组指针
	int i = 0;
	int n = 3;
	for (i = 0; i < n; i++)
	{
		int flag = fputs(buf[i], fp);
		printf("flag = %d\n", flag ); //写入标志位,成功为0
	}
	return 0;
 } 
/*
flag = 0
flag = 0
flag = 0
*/

2)读文件

#include <stdio.h>

char * fgets(char * str, int size, FILE * stream);

功能:从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 '\0' 作为字符串结束。

参数:

str:字符串

size:指定最大读取字符串的长度(size - 1)

stream:文件指针

返回值:

成功:成功读取的字符串

读到文件尾或出错: NULL

#include<stdio.h>
#include<string.h>

int main()
{
	//
	FILE* fp =NULL;  //创建文件指针 
	fp = fopen("01.txt","r");// 打开文件,成功返回文件指针 
	char buf[100] = {0}; //定义并初始化字符数组 
	
	while (!feof(fp)) //文件结束标志符:!0;没有结束返回0值 
	{
		memset(buf, 0, sizeof(buf));///将申请到空间清0
		char *p = fgets(buf, sizeof(buf), fp);//从fp指定文件内容读取siezof(buf)长度的字符,保存到buf所指向的内存空间 
		if (p != NULL)  //读到fp文件结果:p=NULL 
		{
			printf("buf = %s", buf);
		}
	}
	return 0;
 } 
/*
buf = asdfsdf
buf = asdfasd
buf = asdfasdf
buf = asdfadfgh
*/

3)训练:文件版四则运算

有个文件大小不确定,每行内容都是一个四则运算表达式,还没有算出结果,写一个程序,自动算出其结果后修改文件。

#include<stdio.h>
#include<string.h>

void write_file()
{
	//1、打开文件 
	FILE *fp = fopen("03.txt","w"); 
	//2、写文件 
	fputs("10+10=\n",fp);
	fputs("10-10=\n",fp);
	fputs("10*10=\n",fp);
	fputs("10+5=\n",fp);
	fputs("10-6=\n",fp);
	fputs("10/2=",fp);//不加\n,最后为文件结束符可能提前退出循环导致最后一行没有读取
	 

	//3、关闭文件
	fclose(fp); 	
	
	
}

int calc(int a,int b,char ch)
{
	switch(ch)
	{
		case '+':
		return a+b;
		case '-':
		return a-b;
		case '*':
		return a*b;
		case '/':
		return a/b;
		default :
			return 0;
	}
	return 0;
 } 

void read_file()
{
		//1、打开文件 
	FILE *fp = fopen("03.txt","r"); 
	//2、读文件 
	char buf[1024];
	char tmp[1024*4]={0};
	while(1)
	{
		memset(buf,0,sizeof(buf));
		//遇到\n,文件结束符,出错,结束本次读取 
		fgets(buf,sizeof(buf),fp);
		if(strlen(buf)>0)//对读取的内容判断是否为空,不为空打印,解决上面漏掉最后一行 
		{
		  //printf("buf=%s",buf);	
		  
		  int a,b;
		  char ch;
		  sscanf(buf,"%d%c%d=\n",&a,&ch,&b);//从buf里的字符串读取格式化输入 
		  sprintf(buf,"%d%c%d=%d\n",a,ch,b,calc(a,b,ch)); //格式化输出 
		  strcat(tmp,buf);//字符追加函数:把buf所指向的字符串追加到tmp所指向的字符串结尾 
		}
		
		//如果文件结束,跳出循环
		if(feof(fp))
		{
			break; 
		 } 
		 	
	 } 
	 //printf("%s",tmp);

	//3、关闭文件
	fclose(fp); 
	//关闭文件后,以“w”重新打开,目的是清空文件,重新写内容 
		fp = fopen("03.txt","w"); 
		fputs(tmp,fp); //按行输出文件指针fp所指向文件内容 
	
 } 
int main()
{
	//1、打开文件	
	//2、读文件	 
	write_file();
	read_file();
	
	return 0;
}
/*
10+10=20
10-10=0
10*10=100
10+5=15
10-6=4
10/2=5
*/

按照格式化文件fprintf、fscanf

1)写文件

#include <stdio.h>

int fprintf(FILE * stream, const char * format, ...);

功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0'  为止。

参数:

stream:已经打开的文件

format:字符串格式,用法和printf()一样

返回值:

成功:实际写入文件的字符个数

失败:-1

fprintf(fp,"%d %d %d\n", 1,2,3);

2)读文件

#include <stdio.h>

int fscanf(FILE * stream, const char * format, ...);

功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。

参数:

stream:已经打开的文件

format:字符串格式,用法和scanf()一样

返回值:

成功:参数数目,成功转换的值的个数

失败: - 1

int a = 0;
int b = 0;
int c = 0;
fscanf(fp, "%d %d %d\n", &a, &b, &c);
printf("a = %d, b = %d, c = %d\n", a, b, c);

3)训练:文件版排序

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
//1、sprintf使用方法,
//2、利用随机种子产生随机数,
//3、定义数组(堆区空间分配内存),尝试使用动态数组,在栈区分配内存
//1、sscanf使用方法, 
//2、feof判断文件结尾,
//3、文件中每行数字后的\n,通过 sscanf函数读取, 
#define M 500

void readfile()
{
		FILE *fp = fopen("05.txt","w"); 
	
	//产生500随机数,/将随机数转换成字符写入文件,每行写一个
	srand((unsigned int)time(NULL));//随机种子 
	char str[M];
	int num;
	//str = (int *)malloc(M*1);
	int i =0;
	for(i=0;i<M;i++)
	{
	//str1[i]=rand() % 100 +1;
	num=rand() % 100 ;
	//格式化一个字符串 
	sprintf(str,"%d\n",num);
	//往文件写内容 
	fputs(str,fp);
	//	fputs(str,stdout);
	}
	//关闭文件 
	fclose(fp);
	
}


void writefile()	
{
		//读出文件
	
		FILE *fp = fopen("05.txt","r"); 
		if(fp==NULL)//打开失败
		{
			perror("writefile fopen");
			return;
		 } 
		int num,i;
		int a[1024];
		char buf[M];
	for(i=0;i<M;i++)
		//	while(1)
		{
			//读取一行内容,放在buf中,包含\n也读取进去 
			fgets(buf,sizeof(buf),fp);
			if(feof(fp))//如果到饿了文件结尾,跳出循环 
			{
				break;
			}
			sscanf(buf,"%d\n",&a[i]);
			//a[i]=num;
		//	i++;
		}
		int n =i;//数组元素个数
		int j=0; 
		printf("n = %d\n",n);
		//数组排序
		int tmp;
		for(i=0;i<n-1;i++)
		{
			for(j=0;j<n-1-i;j++)
			{
				if(a[j]>a[j+1])
				{
					tmp=a[j];
					a[j]=a[j+1];
					a[j+1]=tmp;
				}
				
			 } 
		}
		 
		char dst[4*1024]={0};
		char src[512]; 
		//for(int i=0;i<n;i++)//bug 可能i有重复定义
		 for(i=0;i<n;i++)
		{
			//printf("%d ",a[i]);
			sprintf(src,"%d\n",a[i]);
			//printf("src = %s",src);
			strcat(dst,src);
		}
		printf("\n");
		//关闭文件 
	fclose(fp);
	//关闭文件,重新写文件
	fp = fopen("05.txt","w");
	
	fputs(dst,fp);
	 
	 fclose(fp);
		
		
}
	
int main()
{
	//打开文件
	readfile();
	//读出文件
	writefile();
	return 0;
 } 

按照块读写文件fread、fwrite

1)写文件

#include <stdio.h>

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:以数据块的方式给文件写入内容

参数:

ptr:准备写入文件数据的地址

size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小

nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb

stream:已经打开的文件指针

返回值:

成功:实际成功写入文件数据的块数,此值和nmemb相等

失败:0

#include<stdio.h>

typedef struct Stu
{
	char name[50];
    	int id;
}Stu;

int main(){
    FILE *fp=NULL;
    fp = fopen("03.txt", "w");

    Stu s[3];
    int i = 0;
    for (i = 0; i < 3; i++)
    {
    	sprintf(s[i].name, "stu%d%d%d", i, i, i);//格式化输出
    	s[i].id = i + 1;
    }

    int ret = fwrite(s, sizeof(Stu), 3, fp);//s写入数据首地址,数据占内存字节数、写入文件个数、文件指针
    printf("ret = %d\n", ret);

}

2)读文件

#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:以数据块的方式从文件中读取内容

参数:

ptr:存放读取出来数据的内存空间

size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小

nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb

stream:已经打开的文件指针

返回值:

成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。

失败:0

#include<stdio.h>

typedef struct Stu
{
	char name[50];
    	int id;
}Stu;

int main(){
    FILE *fp=NULL;
    fp = fopen("03.txt", "r");

    Stu s[3];
    int i = 0;

    int ret = fread(s, sizeof(Stu), 3, fp);//
    printf("ret = %d\n", ret);
	for (i = 0; i < 3; i++)
	{
	printf("s = %s, %d\n", s[i].name, s[i].id);
}

}

3)训练:大文件拷贝

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值