C语言再学习 -- 文件

文件是什么

一个文件(file)通常就是磁盘上的一段命名的存储区。C 将文件看成是连续的字节序列,其中每一个字节都可以单独地读取。

二进制和文本模式
1、在windows系统中,文本模式下,文件以"\r\n"代表换行。若以文本模式打开文件,并用fputs等函数写入换行符"\n"时,函数会自动在"\n"前面加上"\r"。即实际写入文件的是"\r\n" 。

2、在类Unix/Linux系统中文本模式下,文件以"\n"代表换行。所以Linux系统中在文本模式和二进制模式下并无区别。

标准文件

C 程序自动打开3个文件。这3个文件被称为标准输入,标准输出和标准错误输出。默认的标准输入是系统的一般输入设备,通常为键盘;默认的标准输出和标准错误输出是系统的一般输出设备,通常为显示器,分别得到文件描述符 0, 1, 2.

下面的方法从标准输入(键盘)获得一个字符:  ch = getchar ( );

标准文件指针:

stdio.h文件把3个文件指针与3个C 程序自动打开的标准文件进行了并联,如下表所示:

标准文件  

文件指针  

一般使用的设备  

标准输入

stdin

键盘

标准输出

stdout

显示器

标准错误

stderr

显示器

这些指针都是FILE指针类型,所以可以被用作标准I/O函数的参数。


stdout和stderr比较:

stderr -- 标准错误输出设备
stdout -- 标准输出设备 (printf("..")) 同 stdout。
两者默认向屏幕输出。但如果用转向标准输出到磁盘文件,则可看出两者区别。stdout输出到磁盘文件,stderr在屏幕,例如:
fprintf(stderr, "Can't open it!\n");
fprintf(stdout, "Can't open it!\n");
在my.exe
Can't open it!
Can't open it!
Can't open it!

转向标准输出到磁盘文件tmp.txt
my.exe > tmp.txt
Can't open it!

用TYPE 看 tmp.txt的内容:
TYPE tmp.txt
Can't open it!
Can't open it!


stderr是不缓存的,stdout是行间缓存的。请注意:
for(i = 0; i < 10; i++)
    {
      fprintf(stdout, "This is stdout[%d]", i);
      fprintf(stderr, "This is stderr[%d]", i);
    }
会全部显示stderr之后,再显示stdout。又因为stdout是行内缓存,所以加 \n 后会立刻显示。


文件操作分成如下三个步骤:

1、打开文件 (fopen)

2、操作文件 (fread/fwrite)

3、关闭文件 (fclose)

下面来一一介绍:

打开文件 -- fopen ( )函数:

函数原型:
FILE * fopen(const char * path,const char * mode);

返回值:

文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中。
一般而言,打开文件后会做一些文件读取或写入的动作,若打开文件失败,接下来的读写动作也无法顺利进行,所以一般在fopen()后作错误判断及处理

参数说明:

path:字符串包含欲打开的文件路径及文件名

mode:C 字符串,包含了文件访问模式,模式如下:

模式字符串

 

“r”

以只读方式打开文件,该文件必须存在

“r+”

以只读写方式打开文件,该文件必须存在

“w”

打开只写文件,若文件存在则文件长度清零,即该文件内容会消失。

若文件不存在则建立该文件

“w+”

打开可读写文件,若文件存在则文件长度清零,即该文件内容会消失。

若文件不存在则建立该文件。

“a”

以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,

写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)

“a+”

以附加方式打开可读写的文件。若文件不存在,则会建立文件,如果文件存在,

写入的数据会被加到文件尾后,即文件原先的内容会被保留。(原来的EOF符不保留)

“rb”, “wb”, “ab”, “ab+”, “a+b”,

 “wb+”, “w+b”, “ab+”, “a+b”

与前面的模式相似,只是使用二进制模式而非文本模式打开文件


关闭文件 -- fclose ( )函数:

函数原型:

int fclose( FILE *fp );

返回值:
如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)

因此,可在fclose(fp)后使用
if(fclose())
{
    perror("fclose");
}
来判断是否成功关闭文件,关闭失败,则fclose返回“1”并输出出错原因。

扩展:C语言再学习 -- EOF与feof函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 示例一:  
  2. #include<stdio.h>  
  3. int main(void)  
  4. {  
  5.     FILE*fp = NULL;  
  6.     fp = fopen("abc.txt""r");  
  7.     if(NULL == fp)  
  8.     {  
  9.     perror("error...");  
  10.         exit (1);  
  11.     }  
  12.     fclose (fp);  
  13.     fp = NULL;  
  14.      return 0;  
  15. }  


在文件操作时,需要注意以下几点问题
1、在定义文件指针时,要将文件指针指向空;如 FILE *fp = NULL;
2、需要判断文件是否打开成功,如 if(NULL == fp)
3、文件操作完成后,注意要将文件关闭,否则会造成文件所占用内存泄露和在下次访问文件时出现问题。
4、文件关闭后,需要将文件指针指向空,这样做会防止出现游离指针,而对整个工程造成不必要的麻烦;如:fp = NULL;

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 一个简单的文件压缩程序  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5.   
  6. #define LEN 40  
  7. int main (int argc, char *argv[])  
  8. {  
  9.     FILE *in, *out;  
  10.     int ch;  
  11.     char name[LEN];  
  12.     int count = 0;  
  13.   
  14.     if (argc < 2)  
  15.     {  
  16.         fprintf (stderr, "Usage: %s filename\n", argv[0]);  
  17.         exit (1);  
  18.     }  
  19.     if ((in = fopen (argv[1], "r")) == NULL)  
  20.     {  
  21.         fprintf (stderr, "I couldn't open the file \"s\"\n", argv[1]);  
  22.         exit (2);  
  23.     }  
  24.   
  25.     strcpy (name, argv[1]);  
  26.     strcat (name, ".red");  
  27.     if ((out = fopen (name, "w")) == NULL)  
  28.     {  
  29.         fprintf (stderr, "Can't Create output file.\n");  
  30.         exit (3);  
  31.     }  
  32.     while ((ch = getc (in)) != EOF)  
  33.         if (count++ % 3 == 0)  
  34.             putc (ch, out);  
  35.     if (fclose (in) != 0 || fclose (out) != 0)  
  36.         fprintf (stderr, "Error in closing files\n");  
  37.     return 0;  
  38. }  
  39.   
  40. 同一目录下创建文件eddy,里面添加内容 So even Eddy came oven ready .  
  41. 输出结果:创建 eddy.red  
  42. Send money  


操作文件 -- fread ( )函数和fwrite ( )函数

fwrite ( )函数

函数功能:
指向文件写入一个数据块。
函数原型:
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
注意:这个函数以二进制形式对文件进行操作,不局限于文本文件
参数:
(1)buffer:是一个指针,对fwrite来说,是要获取数据的地址;
(2)size:要写入内容的单字节数;(size_t是sizeof返回的类型,通常是unsigned int类型)
(3)count:要进行写入size字节的数据项的个数;
(4)stream:目标文件指针;
返回值:
返回实际写入的数据块数目 count。


fread ( )函数:

函数原型
size_t fread ( void *buffer, size_t size, size_t count, FILE *stream);
参数:
(1)buffer:用于接收数据的内存地址
(2)size:要读的每个数据项的字节数,单位是字节 (size_t是sizeof返回的类型,通常是unsigned int类型)
(3)count:要读count个数据项,每个数据项size个字节.
(4)stream:输入流
返回值:
返回真实写入的项数,若大于count则意味着产生了错误。另外,产生错误后,文件位置指示器是无法确定的。若其他stream或buffer为空指针,或在unicode模式中写入的字节数为奇数,此函数设置errno为EINVAL以及返回0.
函数功能:
从一个文件流中读数据,最多读取count个项,每个项size个字节,如果调用成功返回实际读取到的项个数(小于或等于count),如果不成功或读到文件末尾返回 0。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. int main()  
  4. {  
  5.    FILE *fp;  
  6.    char c[] = "This is w3cschool";  
  7.    char buffer[20];  
  8.   
  9.    /* 打开文件用于读写 */  
  10.    fp = fopen("file.txt""w+");  
  11.   
  12.    /* 写入数据到文件 */  
  13.    fwrite(c, strlen(c) + 1, 1, fp);  
  14.   
  15.    /* 查找文件的开头 */  
  16.    fseek(fp, SEEK_SET, 0);  
  17.   
  18.    /* 读取并显示数据 */  
  19.    fread(buffer, strlen(c)+1, 1, fp);  
  20.    printf("%s\n", buffer);  
  21.    fclose(fp);  
  22.    return(0);  
  23. }  


随机存取:fseek ( )、ftell ( )、rewind ( )

fseek ( )函数

函数功能:

重定位流(数据流/文件)上的文件内部位置指针

注意:文件指针指向文件/流。位置指针指向文件内部的字节位置,随着文件的读取会移动,文件指针如果不重新赋值将不会改变或指向别的文件。

函数原型:

int fseek(FILE *stream, long offset, int fromwhere);

参数:

(1)stream:为文件指针
(2)offset:为偏移量,正数表示正向偏移,负数表示负向偏移(数字值用3L、10L等,L后缀表示long类型)
(3)origin:设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
SEEK_SET: 文件开头
SEEK_CUR: 当前位置
SEEK_END: 文件结尾
其中SEEK_SET,SEEK_CUR和SEEK_END依次为0,1和2.

返回值:

成功,返回 0,失败返回 -1,并设置error的值,可以用perror()函数输出错误。

函数描述:

函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。

上面这句话意思是,函数执行之后,文件指针就移动到了fromwhere + offset位置处,如果offset超过文件自身大小,则不改变stream指向的位置。

fseek函数和lseek函数类似,但lseek返回的是一个off_t数值,而fseek返回的是一个整型.

#include <stdio.h>
int main (void)
{
	char ch = 0;
	FILE *fp = fopen ("abc.txt", "r");
	if (fp)
	{
		//ABCDEFGHIGKLMN
		fseek (fp, 2L, SEEK_SET); //文件开头  (ABC)
		//(2+0 = 2 文件指针移动到2的位置)
		fread (&ch,sizeof (char), 1, fp);
		printf ("%c\n", ch);
 
 		fseek (fp, 3L, SEEK_CUR); //当前位置 (CDEFG)
 		//(3+1 = 4 文件指针移动到4的位置)
 		fread (&ch,sizeof (char), 1, fp); 
 		printf ("%c\n", ch);
 		
 		fseek (fp, -3L, SEEK_END); //文件结尾 MN) 
 		//(-3+2 = -1 文件指针移动到-1位置)
 		fread (&ch,sizeof (char), 1, fp); 
 		printf ("%c\n", ch);
 		
 		fclose (fp); 
 		fp = NULL;
	} 
	return 0;
}
输出结果:
C
G
M

ftell ()函数

函数原型:

long ftell(FILE *stream);

函数功能:
函数 ftell() 用于得到文件位置指针当前位置相对于文件首的偏移字节数。在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置。使用fseek函数后再调用函数ftell()就能非常容易地确定文件的当前位置。

返回值:

以一个long类型值返回一个文件的当前位置。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。

调用示例编辑:
ftell(fp);利用函数 ftell() 也能方便地知道一个文件的长。如以下语句序列: fseek(fp, 0L,SEEK_END); len =ftell(fp); 首先将文件的当前位置移到文件的末尾,然后调用函数ftell()获得当前位置相对于文件首的位移,该位移值等于文件所含字节数。

#include <stdio.h>
int main (void)
{
	FILE *fp;
	int len;
	//ABCDEF
	fp = fopen ("abc.txt", "r");
	if (fp == NULL)
	{
		perror ("error");
		return -1;
	}
	fseek (fp, 0, SEEK_END);
	len = ftell (fp);
	fclose (fp);
	printf ("abc.txt 的总大小 = %d 字节\n", len);
	return 0;
}

输出结果:
abc.txt 的总大小 = 8 字节


rewind ()函数:

函数原型:
void rewind(FILE *stream)
返回值:
该函数不返回任何值。
函数功能: 
将文件内部的位置指针重新指向一个流(数据流/文件)的开头
注意:不是文件指针而是文件内部的位置指针,随着对文件的读写文件的位置指针(指向当前读写字节)向后移动。而文件指针是指向整个文件,如果不重新赋值文件指针不会改变。
rewind函数作用等同于 (void)fseek(stream, 0L, SEEK_SET);[1] 

#include <stdio.h>

int main()
{
   char str[] = "Hello World!";
   FILE *fp;
   int ch;

   /* 首先让我们在文件中写入一些内容 */
   fp = fopen( "file.txt" , "w" );
   fwrite(str , 1 , sizeof(str) , fp );
   fclose(fp);

   fp = fopen( "file.txt" , "r" );
   while(1)
   {
      ch = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", ch);
   }
   
   rewind(fp); //从头从新开始打印
  
   printf("\n");
   while(1)
   {
      ch = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", ch);
     
   }
   printf ("\n");
   fclose(fp);

   return(0);
}
输出结果:
Hello World!
Hello World!



  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聚优致成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值