0
点赞
收藏
分享

微信扫一扫

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函数



    1. 示例一:  
    2. #include<stdio.h>  
    3. int main(void)  
    4. {  
    5. FILE*fp = NULL;  
    6. "abc.txt", "r");  
    7. if(NULL == fp)  
    8.     {  
    9. "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;


    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. "Usage: %s filename\n", argv[0]);  
    17.         exit (1);  
    18.     }  
    19. if ((in = fopen (argv[1], "r")) == NULL)  
    20.     {  
    21. "I couldn't open the file \"s\"\n", argv[1]);  
    22.         exit (2);  
    23.     }  
    24.   
    25.     strcpy (name, argv[1]);  
    26. ".red");  
    27. if ((out = fopen (name, "w")) == NULL)  
    28.     {  
    29. "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. "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。



    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. "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. "%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!




    举报

    相关推荐

    0 条评论