利用标准C语言库函数进行文本文件读写

C 专栏收录该内容
11 篇文章 0 订阅

    利用C语言进行文件操作的方法有多种。其中包括在UNIX系统环境下利用系统接口进行文件操作;在windows系统下可以利用windows系统下可以利用fopen_s等库函数的安全版本进行文件操作。但是用的最多的就是利用标准库函数进行文件操作。本文主要介绍利用C标准库函数进行文件的打开、读取(一次一个字符、一次一行、格式化读)、写入(一次写入一个字符、一次写一行、格式化写)和关闭操作。其中这些库函数都包含在头文件<stdio.h>中。

   启动一个C语言程序时,操作系统环境会打开标准输入、标准输出和标准错误3个文件,相应的文件指针分别为stdin、stdout和stderr(文件指针stdin/stdout都是FILE*类型的对象,但他们是常量而非变量,不能对它们赋值)。在大多数环境中,stdin指向键盘,而stdout和stderr指向显示器。当然也可以被重定向到文件或者管道。

一、文件打开

1、fopen

1)函数原型:

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

2)参数

第一个参数是一个字符串,它包含文件名。第二个参数也是字符串,表示的是访问模式。允许的模式包括:

“r”

如果文件不存在,打开失败

"w"

如果文件存在,把文件截断至0长;如果文件不存在,会创建文件

"a"

追加

如果文件存在,在文件尾进行写;如果文件不存在会创建文件

"r+"

读和写

如果文件不存在,打开失败

"w+"

读和写

如果文件存在,把文件截断至0长;如果文件不存在,会创建文件

"a+"

读和追加

如果文件存在,在文件尾进行写;如果文件不存在会创建文件

默认的是操作文本文件;如果在以上的模式中加上"b"例如:“rb”,"wb","ab+"等则表示操作二进制格式的文件。但是因为UNIX内核并不对这两种文件进行区分因此在UNIX系统环境下指定字符"b"作为模式的一部分并无意义。

3)返回值

若打开成功则返回一个指向FILE对象的指针;若打开失败则返回NULL。

(FILE通常是一个结构,它包含了标准I/O库为管理该流需要的所有信息,包括用于实际I/O的文件描述符、指向用于该流缓冲区的指针、缓冲区的长度、当前缓冲区的字符数以及出错标志等。

 但是在本例中FILE像int一样是一个类型名,而不是结构标记)

4)示例

#include <stdio.h>
FILE *stream, *stream2;
void main( void )
{
   int numclosed;
   /* Open for read (will fail if file "data" does not exist) */
   if( (stream  = fopen( "data", "r" )) == NULL )
      printf( "The file 'data' was not opened\n" );
   else
      printf( "The file 'data' was opened\n" );
   /* Open for write */
   if( (stream2 = fopen( "data2", "w+" )) == NULL )
      printf( "The file 'data2' was not opened\n" );
   else
      printf( "The file 'data2' was opened\n" );
   /* Close stream */
   if(fclose( stream2 ))
	 printf( "The file 'data2' was not closed\n" );
   /* All other files are closed: */
   numclosed = _fcloseall( );
   printf( "Number of files closed by _fcloseall: %u\n", numclosed );
}
执行结果:



二、读文件(读流)

1、一次读一个字符

(1)fgetc

1)函数原型

int fgetc( 
   FILE* stream 
);

2)返回值

若成功返回下一个字符,若已到达文件尾端或者出错返回EOF;

①返回下一个字符时,将其unsigned char 类型转换为int类型。返回整型的原因是可能会需要返回已出错或已达文件尾端的指示值EOF(通常为-1)。

②不管出错还是到达尾端返回的都是EOF。为了区分这两种情况,可以调用 int ferror(FILE *fp)或者int feof(FILE *fp)来进行判断(若是真返回非0,否则返回0)。

3)示例

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   FILE *stream;
   char buffer[81];
   int  i, ch;

   /* Open file to read line from: */
   if( (stream = fopen( "fgetc.c", "r" )) == NULL )
      exit( 0 );

   /* Read in first 80 characters and place them in "buffer": */
   ch = fgetc( stream );
   for( i=0; (i < 80 ) && ( feof( stream ) == 0 ); i++ )
   {
      buffer[i] = (char)ch;
      ch = fgetc( stream );
   }

   /* Add null to end string */
   buffer[i] = '\0';
   printf( "%s\n", buffer );
   fclose( stream );
}

(2)getc

int getc( 
   FILE *stream 
);
getc()与fgetc()使用方法相同。区别是getc可被实现为宏,而fgetc不能实现为宏。

因此:①getc的参数不应该是有副作用的表达式,因为可能会被计算多次 ;

            ②fgetc是函数,因此可以得到其地址 ;

            ③fgetc的所需时间可能会比getc要长。

(3)getchar

int getchar(
    void 
);
getchar用来从标准输入中读取数据;被实现为宏而不是函数。例如:

#define getchar() getc(stdin)

2、一次读一行

(1)fgets

1)函数原型

char *fgets( 
   char* string, 
   int n, 
   FILE *stream 
);
2)参数

string:读取后存放的缓冲区地址;n:缓冲区长度;stream:要读的文件指针

3)返回值

若到达文件尾或者出错返回NULL;

若读取成功返回读取的字符串。其中以行为单位进行读取,读入的字节放入缓冲区。若一行中包括最后一个换行符的字符数大于n-1个;则fgets值返回不完整的行,对fgets的下次调用会继续读该行。缓冲区总是以NULL字节结尾。

4)示例

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char line[5];

   if( (stream = fopen( "fgets.c", "r" )) != NULL )
   {
	   while(fgets(line,5,stream)!=NULL)
	   {
         printf( "%s", line);
	   }
	   printf("\n");
      fclose( stream );
   }
}
输出(与fgets.c中的文件格式相同):


若只执行一次fgets输出的是:/* f
(2)gets

char *gets( 
   char* buffer 
);
gets从标准输入读,但是不推荐使用该函数。因为gets没有指定缓冲区长度,这样如果一行的长度大于缓冲区的长度就有可能照成缓冲区溢出。

gets与fgets的另一个区别是gets并不将换行符存入缓冲区。

3、格式化读

(1)fscanf

1)函数原型

int fscanf( 
   FILE* stream, 
   const char* format [, argument ]... 
);
2)参数

format:控制如何转换参数,以便对它们赋值。格式与scanf中的格式控制相同。

argument:包含各变量的地址,用转换结果对这些变量赋值。

3)返回值

返回赋值的输入项数;若输入错误(格式不匹配)或任意转换前已经到达文件尾端,返回EOF。

4)示例

#include <stdio.h>

FILE *stream;

void main( void )
{
   long l;
   float fp;
   char s[81];
   char c;

   stream = fopen( "fscanf.out", "w+" );
   if( stream == NULL )
      printf( "The file fscanf.out was not opened\n" );
   else
   {
      fprintf( stream, "%s %ld %f%c", "a-string", 
               65000, 3.14159, 'x' );

      /* Set pointer to beginning of file: */
      fseek( stream, 0L, SEEK_SET );

      /* Read data back from file: */
      fscanf( stream, "%s", s );
      fscanf( stream, "%ld", &l );

      fscanf( stream, "%f", &fp );
      fscanf( stream, "%c", &c );

      /* Output data read: */
      printf( "%s\n", s );
      printf( "%ld\n", l );
      printf( "%f\n", fp );
      printf( "%c\n", c );

      fclose( stream );
   }
}
输出:


三、文件写

1、一次写一个字符

(1)fputc

与输入函数fgetc相对应

1)函数原型

int fputc( 
   int c, 
   FILE* stream 
);

2)返回值

若成功返回 c;若出错返回EOF。
3)示例

/* FPUTC.C: This program uses fputc and _fputchar
 * to send a character array to stdout.
 */

#include <stdio.h>

void main( void )
{
   char strptr1[] = "This is a test of fputc!!\n";
   char strptr2[] = "This is a test of _fputchar!!\n";
   char *p;

   /* Print line to stream using fputc. */
   p = strptr1;
   while( (*p != '\0') && fputc( *(p++), stdout ) != EOF ) ;

   /* Print line to stream using _fputchar. */
   p = strptr2;
   while( (*p != '\0') && _fputchar( *(p++) ) != EOF )
      ;
}
(2)putc

int putc(
   int c,
   FILE *stream 
);
与getc相对应;被实现为宏;fputc不能实现为宏

示例:

/* This program uses putc to write buffer
 * to a stream. If an error occurs, the program
 * stops before writing the entire buffer.
 */

#include <stdio.h>

int main( void )
{
   FILE *stream;
   char *p, buffer[] = "This is the line of output\n";
   int  ch;

   ch = 0;
   /* Make standard out the stream and write to it. */
   stream = stdout;
   for( p = buffer; (ch != EOF) && (*p != '\0'); p++ )
      ch = putc( *p, stream );
}
 
(3)putchar

与getchar想对应;putchar(c)等同于putc(c,stdout);被实现为宏

2、一次写一行

(1)fputs

与fgets相对应

1)函数原型

int fputs( 
   const char* string, 
   FILE* stream 
);
2)返回值

若成功返回非负值,若失败返回EOF

fputs将以NULL字节终止的字符串写到指定的流;尾端的终止符NULL不写出。注意:这并不是每次每次输出一行,因为字符串 不需要换行符作为最后一个非NULL字节。

3)示例

/* FPUTS.C: This program uses fputs to write
 * a single line to the stdout stream.
 */

#include <stdio.h>

void main( void )
{
   fputs( "Hello world from fputs.\n", stdout );
}
(2)puts

与gets相对应。

int puts( 
   const char* string 
);
puts将一个以NULL字节终止的字符串写到标准输出,终止符不写出。但是随后会将一个换行符写到标准输出。

与gets不同puts是安全的。但是要注意最后添加的换行符。

3、格式输出

(1)fprintf

与fscanf相对应

1)函数原型

int fprintf( 
   FILE* stream, 
   const char* format [, argument ]...
);
将数据格式化写字stream流

2)示例

/* FPRINTF.C: This program uses fprintf to format various
 * data and print it to the file named FPRINTF.OUT. 
 */

#include <stdio.h>

FILE *stream;

void main( void )
{
   int    i = 10;
   double fp = 1.5;
   char   s[] = "this is a string";
   char   c = '\n';

   stream = fopen( "fprintf.out", "w" );
   fprintf( stream, "%s%c", s, c );
   fprintf( stream, "%d\n", i );
   fprintf( stream, "%f\n", fp );
   fclose( stream );
}

四、文件关闭

1、fclose

(1)函数原型

int fclose( 
   FILE* stream 
);
(2)返回值

如果成功关闭返回0;若出错返回EOF.

(3)说明

在文件被关闭之前,会冲洗缓冲中的输出数据。缓冲区中的任何输入数据被丢弃。如果标准I/O库已经为该流自动分配了一个缓冲区,则释放此缓冲区。

2、_fcloseall

(1)函数原型

int _fcloseall( 
   void 
);
(2)返回值
如果成功则返回关闭的流的数目;失败时返回EOF

(3)说明

函数会关闭除stdin、stdout以及stderr外的所有文件流;其中包括由tepfile创建的临时文件。


参考资料:

1、MSDN

2、《UNIX环境高级编程》

3、《C程序设计语言》



  • 29
    点赞
  • 0
    评论
  • 49
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值