0
点赞
收藏
分享

微信扫一扫

结构体--共用体--枚举 之难点——链表 奋力学习嵌入式的第十六天

鲤鱼打个滚 2024-02-02 阅读 13

cstdio,在C语言中称为stdio.h。该库使用所谓的与物理设备(如键盘、打印机、终端)或系统支持的任何其他类型的文件一起操作。

在本文将会通过介绍函数参数,举出实际的简单例子来帮助大家快速上手使用函数。

目录

一、流

 二、库函数

1、File access(文件访问)

 fclose:

fflush :

fopen:

freopen:

setbuf :

setvbuf :

2、Operations on files(对文件的操作)

remove:

 rename:

 tmofile:

tmpnam:

3、Formatted input/output(格式化的输入/输出)

fprintf:

fscanf:

snprintf :

 sprintf:

sscanf:

vfprintf:

vfscanf:

vprintf:

vscanf:

vsnprintf:

vsprintf:

4、Character input/output:(字符输入/输出)

fgetc:

fgets:

 fputc:

fputs:

getc:

 getchar:

gets:

putc:

putchar:

ungetc:

5、Direct input/output(直接输入/输出)

fread:

fwrite:

6、Error-handling(错误处理)

clearerr:

feof:

ferror:

perror:

7、Types(类型)

FILE:

fpos_t:

size_t:

二、小结


一、流

        在C语言的标准库stdio.h中,流(stream)是一个抽象的概念,用于表示输入和输出流。在C语言中,流是用来处理文件输入和输出的抽象实体,它可以是标准输入流(stdin)、标准输出流(stdout)或者文件流(file stream)。

        、、stdio.h中定义了一系列函数和宏来操作流,例如fopen()用于打开文件流,fclose()用于关闭文件流,fread()和fwrite()用于读写文件流等。此外,还有一些用于控制流的函数和宏,如fflush()用于刷新输出缓冲区,feof()和ferror()用于检查文件结束符和错误标志等。

        通过使用流,程序可以方便地进行文件的输入输出操作,无论是从键盘读取输入,还是向文件写入数据,都可以通过流来实现。流的使用使得文件操作变得更加灵活和方便,同时也提供了一种统一的接口来处理输入输出操作。

        在程序运行时一般会使用以下三个流:

 二、库函数

1、File access文件访问

 fclose:

用于关闭文件与流的联系

/* fclose example */
#include <stdio.h>
int main ()
{
  FILE * pFile;
  pFile = fopen ("myfile.txt","wt");
  fprintf (pFile, "fclose example");
  fclose (pFile);//成功返回0,失败返回EOF
  return 0;
}

 ----------------------------------------------------我是分割线-------------------------------------------------------------

fflush :

在C语言中,当你向文件写入数据时,数据通常首先被存储在内存中的缓冲区中,而不是立即写入文件。fflush函数可以强制将缓冲区中的数据写入文件,以确保数据被及时保存。这在某些情况下特别重要,比如在程序终止之前需要确保所有数据都已经写入文件时。

/* fflush example */
#include <stdio.h>
char mybuffer[80];
int main()
{
   FILE * pFile;
   pFile = fopen ("example.txt","r+");
   if (pFile == NULL) perror ("Error opening file");
   else {
     fputs ("test",pFile);
     fflush (pFile);    // flushing or repositioning required
     fgets (mybuffer,80,pFile);
     puts (mybuffer);
     fclose (pFile);
     return 0;
  }
}

 ----------------------------------------------------我是分割线-------------------------------------------------------------

fopen:

打开文件

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

        打开其名称在参数 filename 中指定的文件,并将其与流相关联,该流可在将来的操作中通过返回的 FILE 指针进行标识。文件名应该包含要打开的文件的名称的 C 字符串。其值应遵循运行环境的文件名规范。
        对流执行的操作以及如何执行这些操作由 mode 参数定义。

以下为mode参数:

 返回值:如果文件已成功打开,该函数将返回指向 FILE 对象的指针,该对象可用于在将来的操作中标识流。否则,将返回 null 指针。

/* fopen example */
#include <stdio.h>
int main ()
{
  FILE * pFile;
  pFile = fopen ("myfile.txt","w");
  if (pFile!=NULL)
  {
    fputs ("fopen example",pFile);
    fclose (pFile);
  }
  return 0;
}

 ----------------------------------------------------我是分割线-------------------------------------------------------------

freopen:

在C语言中,freopen()函数用于重新指定一个已经打开的文件流的文件名和访问模式。这个函数可以用来重新定向一个已经打开的文件流,从而改变该文件流对应的文件。

FILE * freopen ( const char * filename, const char * mode, FILE * stream )

使用freopen()函数可以实现一些文件操作的功能,例如:

  • 重新打开一个文件,从而关闭当前的文件流并将其重新指向另一个文件。
  • 改变文件流的访问模式,例如从只读模式改为只写模式。

        总之,freopen()函数提供了一种方便的方式来重新指定一个已经打开的文件流,从而改变其对应的文件和访问模式。 

 ----------------------------------------------------我是分割线-------------------------------------------------------------

setbuf :

用于为流指定缓冲区,可以提高输入/输出操作的性能。该函数通常用于设置标准输入、标准输出或标准错误流的缓冲区。它接受三个参数:正在设置缓冲区的流、指向缓冲区的指针和缓冲区的大小。setbuf函数对于优化输入/输出操作的性能特别有用,特别是在处理大量数据时。

void setbuf ( FILE * stream, char * buffer )
/* setbuf example */
#include <stdio.h>

int main ()
{
  char buffer[BUFSIZ];
  FILE *pFile1, *pFile2;

  pFile1=fopen ("myfile1.txt","w");
  pFile2=fopen ("myfile2.txt","a");

  setbuf ( pFile1 , buffer );
  fputs ("This is sent to a buffered stream",pFile1);
  fflush (pFile1);

  setbuf ( pFile2 , NULL );
  fputs ("This is sent to an unbuffered stream",pFile2);

  fclose (pFile1);
  fclose (pFile2);

  return 0;
}

        在此示例中,打开两个文件进行写入。与文件 myfile1.txt 关联的流设置为用户分配的缓冲区;对它执行写入操作;数据在逻辑上是流的一部分,但在调用 fflush 函数之前,它尚未写入设备。
示例中与文件 myfile2.txt 关联的第二个缓冲区设置为无缓冲,因此后续输出操作将尽快写入设备。
但是,一旦文件关闭,缓冲流和无缓冲流的最终状态是相同的(关闭文件会刷新其缓冲区)。

  ----------------------------------------------------我是分割线------------------------------------------------------------

setvbuf :

用于设置文件流的缓冲方式,使用 setvbuf 可以控制文件流的缓冲行为,这对于低级 I/O 或对性能有严格要求的程序非常有用。

int setvbuf ( FILE * stream, char * buffer, int mode, size_t size )

详细mode:

返回值:如果成功,函数返回 0;否则,返回一个非零值。

/* setvbuf example */

#include <stdio.h>

int main ()
{
  FILE *pFile;

  pFile=fopen ("myfile.txt","w");

  setvbuf ( pFile , NULL , _IOFBF , 1024 );

  // File operations here

  fclose (pFile);

  return 0;
}

        在此示例中,将创建一个名为 myfile.txt 的文件,并为关联的流请求 1024 字节的完整缓冲区,因此,只有在每次填充 1024 字节缓冲区时,才应将输出到此流的数据写入文件。

2、Operations on files(对文件的操作)

remove:

删除文件

int remove ( const char * filename );

返回值:如果文件已成功删除,则返回零值。失败时,将返回非零值

#include <stdio.h>

int main ()
{
  if( remove( "myfile.txt" ) != 0 )
    perror( "Error deleting file" );
  else
    puts( "File successfully deleted" );
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

 rename:

将 oldname 指定的文件或目录的名称更改为 newname

int rename ( const char * oldname, const char * newname );

返回值:如果文件重命名成功,则返回零值。失败时,将返回非零值。

#include <stdio.h>

int main ()
{
  int result;
  char oldname[] ="oldname.txt";
  char newname[] ="newname.txt";
  result= rename( oldname , newname );
  if ( result == 0 )
    puts ( "File successfully renamed" );
  else
    perror( "Error renaming file" );
  return 0;
}

 ----------------------------------------------------我是分割线------------------------------------------------------------

 tmofile:

打开临时文件。创建一个临时二进制文件,打开以供更新(“wb+”模式,有关详细信息,请参见 fopen),其文件名保证与任何其他现有文件不同。当流关闭 (fclose) 或程序正常终止时,创建的临时文件会自动删除。如果程序异常终止,是否删除文件取决于具体的系统和库实现。

FILE * tmpfile ( void )

返回值:如果成功,该函数将返回指向创建的临时文件的流指针。失败时,返回 NULL。

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

int main ()
{
  char buffer [256];
  FILE * pFile;
  pFile = tmpfile ();

  do {
    if (!fgets(buffer,256,stdin)) break;
    fputs (buffer,pFile);
  } while (strlen(buffer)>1);

  rewind(pFile);

  while (!feof(pFile)) {
    if (fgets (buffer,256,pFile) == NULL) break;
    fputs (buffer,stdout);
  }

  fclose (pFile);
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

tmpnam:

生成临时文件名。返回一个字符串,其中包含与任何现有文件的名称不同的文件名,因此适合安全地创建临时文件,而不会有覆盖现有文件的风险。

char * tmpnam ( char * str );
#include <stdio.h>

int main ()
{
  char buffer [L_tmpnam];
  char * pointer;

  tmpnam (buffer);
  printf ("Tempname #1: %s\n",buffer);

  pointer = tmpnam (NULL);
  printf ("Tempname #2: %s\n",pointer);

  return 0;  
}

----------------------------------------------------我是分割线------------------------------------------------------------

3、Formatted input/output(格式化的输入/输出)

fprintf:

按格式指向的 C 字符串写入。如果 format 包含格式说明符(以 % 开头的子序列),则格式后面的附加参数将格式化并插入到生成的字符串中,以替换它们各自的说明符

int fprintf ( FILE * stream, const char * format, ... );
/* fprintf example */
#include <stdio.h>

int main ()
{
   FILE * pFile;
   int n;
   char name [100];

   pFile = fopen ("myfile.txt","w");
   for (n=0 ; n<3 ; n++)
   {
     puts ("please, enter a name: ");
     gets (name);
     fprintf (pFile, "Name %d [%-10.10s]\n",n+1,name);
   }
   fclose (pFile);

   return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

fscanf:

中读取数据,并根据参数格式将其存储到其他参数所指向的位置。

int fscanf ( FILE * stream, const char * format, ... );
/* fscanf example */
#include <stdio.h>

int main ()
{
  char str [80];
  float f;
  FILE * pFile;

  pFile = fopen ("myfile.txt","w+");
  fprintf (pFile, "%f %s", 3.1416, "PI");
  rewind (pFile);
  fscanf (pFile, "%f", &f);
  fscanf (pFile, "%s", str);
  fclose (pFile);
  printf ("I have read: %f and %s \n",f,str);
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

snprintf :

C 字符串存储在 s 指向的缓冲区中(将 n 作为要填充的最大缓冲区容量)。

int snprintf ( char * s, size_t n, const char * format, ... );
/* snprintf example */
#include <stdio.h>

int main ()
{
  char buffer [100];
  int cx;

  cx = snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );

  if (cx>=0 && cx<100)      // check returned value

    snprintf ( buffer+cx, 100-cx, ", and the half of that is %d.", 60/2/2 );

  puts (buffer);

  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

 sprintf:

功能与snprintf相似,但是没有snprintf安全。

int sprintf ( char * str, const char * format, ... );
/* sprintf example */
#include <stdio.h>

int main ()
{
  char buffer [50];
  int n, a=5, b=3;
  n=sprintf (buffer, "%d plus %d is %d", a, b, a+b);
  printf ("[%s] is a string %d chars long\n",buffer,n);
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

sscanf:

从字符串中读取格式化数据,从 s 读取数据,并根据参数格式将它们存储到附加参数给出的位置,就像使用 scanf 一样,但从 s 读取数据而不是标准输入 (stdin)。

int sscanf ( const char * s, const char * format, ...);
/* sscanf example */
#include <stdio.h>

int main ()
{
  char sentence []="Rudolph is 12 years old";
  char str [20];
  int i;

  sscanf (sentence,"%s %*s %d",str,&i);//添加了*的部分会被忽略,不会被参数获取
  printf ("%s -> %d\n",str,i);
  
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

vfprintf:

将格式化数据从变量参数列表写入流

int vfprintf ( FILE * stream, const char * format, va_list arg );
/* vfprintf example */
#include <stdio.h>
#include <stdarg.h>

void WriteFormatted (FILE * stream, const char * format, ...)
{
  va_list args;
  va_start (args, format);
  vfprintf (stream, format, args);
  va_end (args);
}

int main ()
{
   FILE * pFile;

   pFile = fopen ("myfile.txt","w");

   WriteFormatted (pFile,"Call with %d variable argument.\n",1);
   WriteFormatted (pFile,"Call with %d variable %s.\n",2,"arguments");

   fclose (pFile);

   return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

vfscanf:

将格式化数据从流读取到变量参数列表中,从中读取数据,并根据参数格式将它们存储到 arg 标识的变量参数列表中元素所指向的位置。

int vfscanf ( FILE * stream, const char * format, va_list arg );
/* vfscanf example */
#include <stdio.h>
#include <stdarg.h>

void ReadStuff (FILE * stream, const char * format, ...)
{
  va_list args;
  va_start (args, format);
  vfscanf (stream, format, args);
  va_end (args);
}

int main ()
{
  FILE * pFile;
  int val;
  char str[100];

  pFile = fopen ("myfile.txt","r");

  if (pFile!=NULL) {
    ReadStuff ( pFile, " %s %d ", str, &val );
    printf ("I have read %s and %d", str, val);
    fclose (pFile);
  }

  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

vprintf:

将格式化数据从变量参数列表打印到 stdout,将 format 指向的 C 字符串写入标准输出 (stdout),以与 printf 相同的方式替换任何格式说明符,但使用 arg 标识的变量参数列表中的元素,而不是其他函数参数。

int vprintf ( const char * format, va_list arg );
/* vprintf example */
#include <stdio.h>
#include <stdarg.h>

void WriteFormatted ( const char * format, ... )
{
  va_list args;
  va_start (args, format);
  vprintf (format, args);
  va_end (args);
}

int main ()
{
   WriteFormatted ("Call with %d variable argument.\n",1);
   WriteFormatted ("Call with %d variable %s.\n",2,"arguments");

   return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

vscanf:

将格式化数据读入变量参数列表,从标准输入 (stdin) 读取数据,并根据参数格式将其存储到由 arg 标识的变量参数列表中的元素所指向的位置。

int vscanf ( const char * format, va_list arg )
/* vscanf example */
#include <stdio.h>
#include <stdarg.h>

void GetMatches ( const char * format, ... )
{
  va_list args;
  va_start (args, format);
  vscanf (format, args);
  va_end (args);
}

int main ()
{
  int val;
  char str[100];

  printf ("Please enter a number and a word: ");
  fflush (stdout);
  GetMatches (" %d %99s ", &val, str);
  printf ("Number read: %d\nWord read: %s\n", val, str);

  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

vsnprintf:

将格式化数据从变量参数列表写入大小缓冲区,使用在 printf 上使用 format 时打印的相同文本组成一个字符串,但使用 arg 标识的变量参数列表中的元素而不是其他函数参数,并将生成的内容作为 C 字符串存储在由 s 指向的缓冲区中(将 n 作为要填充的最大缓冲区容量)。

int vsnprintf (char * s, size_t n, const char * format, va_list arg );
/* vsnprintf example */
#include <stdio.h>
#include <stdarg.h>

void PrintFError ( const char * format, ... )
{
  char buffer[256];
  va_list args;
  va_start (args, format);
  vsnprintf (buffer,256,format, args);
  perror (buffer);
  va_end (args);
}

int main ()
{
   FILE * pFile;
   char szFileName[]="myfile.txt";

   pFile = fopen (szFileName,"r");
   if (pFile == NULL)
     PrintFError ("Error opening '%s'",szFileName);
   else
   {
     // file successfully open
     fclose (pFile);
   }
   return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

vsprintf:

将格式化数据从变量参数列表写入字符串,使用在 printf 上使用 format 时打印的相同文本组成一个字符串,但使用 arg 标识的变量参数列表中的元素而不是其他函数参数,并将生成的内容作为 C 字符串存储在 s 指向的缓冲区中。

int vsprintf (char * s, const char * format, va_list arg );
/* vsprintf example */
#include <stdio.h>
#include <stdarg.h>

void PrintFError ( const char * format, ... )
{
  char buffer[256];
  va_list args;
  va_start (args, format);
  vsprintf (buffer,format, args);
  perror (buffer);
  va_end (args);
}

int main ()
{
  FILE * pFile;
  char szFileName[]="myfile.txt";

  pFile = fopen (szFileName,"r");
  if (pFile == NULL)
    PrintFError ("Error opening '%s'",szFileName);
  else
  {
    // file successfully open
    fclose (pFile);
  }
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

vsscanf:

将格式化数据从字符串读取到变量参数列表中,从 s 读取数据,并根据参数格式将它们存储到 arg 标识的变量参数列表中元素所指向的位置。

int vsscanf ( const char * s, const char * format, va_list arg );
/* vsscanf example */
#include <stdio.h>
#include <stdarg.h>

void GetMatches ( const char * str, const char * format, ... )
{
  va_list args;
  va_start (args, format);
  vsscanf (str, format, args);
  va_end (args);
}

int main ()
{
  int val;
  char buf[100];

  GetMatches ( "99 bottles of beer on the wall", " %d %s ", &val, buf);

  printf ("Product: %s\nQuantity: %d\n", buf, val);

  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

4、Character input/output:(字符输入/输出

fgetc:

从流中获取字符。

int fgetc ( FILE * stream );
/* fgetc example: money counter */
#include <stdio.h>
int main ()
{
  FILE * pFile;
  int c;
  int n = 0;
  pFile=fopen ("myfile.txt","r");
  if (pFile==NULL) perror ("Error opening file");
  else
  {
    do {
      c = fgetc (pFile);
      if (c == '$') n++;
    } while (c != EOF);
    fclose (pFile);
    printf ("The file contains %d dollar sign characters ($).\n",n);
  }
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

fgets:

从流中获取字符串。

char * fgets ( char * str, int num, FILE * stream );
/* fgets example */
#include <stdio.h>

int main()
{
   FILE * pFile;
   char mystring [100];

   pFile = fopen ("myfile.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else {
     if ( fgets (mystring , 100 , pFile) != NULL )
       puts (mystring);
     fclose (pFile);
   }
   return 0;
}

 ----------------------------------------------------我是分割线------------------------------------------------------------

 fputc:

将字符写入流。

int fputc ( int character, FILE * stream );
/* fputc example: alphabet writer */
#include <stdio.h>

int main ()
{
  FILE * pFile;
  char c;

  pFile = fopen ("alphabet.txt","w");
  if (pFile!=NULL) {

    for (c = 'A' ; c <= 'Z' ; c++)
      fputc ( c , pFile );

    fclose (pFile);
  }
  return 0;
}

 ----------------------------------------------------我是分割线------------------------------------------------------------

fputs:

将字符串写入流。

int fputs ( const char * str, FILE * stream );
/* fputs example */
#include <stdio.h>

int main ()
{
   FILE * pFile;
   char sentence [256];

   printf ("Enter sentence to append: ");
   fgets (sentence,256,stdin);
   pFile = fopen ("mylog.txt","a");
   fputs (sentence,pFile);
   fclose (pFile);
   return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

getc:

从流中获取字符

int getc ( FILE * stream );
/* getc example: money counter */
#include <stdio.h>
int main ()
{
  FILE * pFile;
  int c;
  int n = 0;
  pFile=fopen ("myfile.txt","r");
  if (pFile==NULL) perror ("Error opening file");
  else
  {
    do {
      c = getc (pFile);
      if (c == '$') n++;
    } while (c != EOF);
    fclose (pFile);
    printf ("File contains %d$.\n",n);
  }
  return 0;
}

 ----------------------------------------------------我是分割线------------------------------------------------------------

 getchar:

从 stdin 获取字符,返回读取的字符。

int getchar ( void );
/* getchar example : typewriter */
#include <stdio.h>

int main ()
{
  int c;
  puts ("Enter text. Include a dot ('.') in a sentence to exit:");
  do {
    c=getchar();
    putchar (c);
  } while (c != '.');
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

gets:

从 stdin 获取字符串,返回获取的字符串(终止 null 字符会自动追加到复制到 str 的字符之后)

char * gets ( char * str );
  • [注意:此函数在 C 或 C++ 中不再可用(从 C11 和 C++14 开始)]
/* gets example */
#include <stdio.h>

int main()
{
  char string [256];
  printf ("Insert your full address: ");
  gets (string);     // warning: unsafe (see fgets instead)
  printf ("Your address is: %s\n",string);
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

putc:

将字符写入流(字符被写在的内部位置指示器指示的位置,然后自动前进一个)

int putc ( int character, FILE * stream );
/* putc example: alphabet writer */
#include <stdio.h>

int main ()
{
  FILE * pFile;
  char c;

  pFile=fopen("alphabet.txt","wt");
  for (c = 'A' ; c <= 'Z' ; c++) {
    putc (c , pFile);
    }
  fclose (pFile);
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

putchar:

将字符写入 stdout(等价于使用 stdout 作为第二个参数调用 putc)

int putchar ( int character );
/* putchar example: printing the alphabet */
#include <stdio.h>

int main ()
{
  char c;
  for (c = 'A' ; c <= 'Z' ; c++) putchar (c);

  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

puts:

将字符串写入 stdout

int puts ( const char * str );
/* puts example : hello world! */
#include <stdio.h>

int main ()
{
  char string [] = "Hello world!";
  puts (string);
}

----------------------------------------------------我是分割线------------------------------------------------------------

ungetc:

从流中取消获取字符

int ungetc(int c, FILE *stream);
/* ungetc example */
#include <stdio.h>

int main ()
{
  FILE * pFile;
  int c;
  char buffer [256];

  pFile = fopen ("myfile.txt","rt");
  if (pFile==NULL) perror ("Error opening file");
  else while (!feof (pFile)) {
    c=getc (pFile);
    if (c == EOF) break;
    if (c == '#') ungetc ('@',pFile);
    else ungetc (c,pFile);
    if (fgets (buffer,255,pFile) != NULL)
      fputs (buffer,stdout);
    else break;
  }
  return 0;
}

----------------------------------------------------我是分割线------------------------------------------------------------

5、Direct input/output(直接输入/输出)

fread:

中读取 count 元素的数组,每个元素的大小为 bytes,并将它们存储在 ptr 指定的内存块中。

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
/* fread example: read an entire file */
#include <stdio.h>
#include <stdlib.h>

int main () {
  FILE * pFile;
  long lSize;
  char * buffer;
  size_t result;

  pFile = fopen ( "myfile.bin" , "rb" );
  if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

  // obtain file size:
  fseek (pFile , 0 , SEEK_END);
  lSize = ftell (pFile);
  rewind (pFile);

  // allocate memory to contain the whole file:
  buffer = (char*) malloc (sizeof(char)*lSize);
  if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

  // copy the file into the buffer:
  result = fread (buffer,1,lSize,pFile);
  if (result != lSize) {fputs ("Reading error",stderr); exit (3);}

  /* the whole file is now loaded in the memory buffer. */

  // terminate
  fclose (pFile);
  free (buffer);
  return 0;
}

 将 myfile.bin 加载到动态分配的内存缓冲区中,该缓冲区可用于将文件的内容作为数组进行操作。

----------------------------------------------------我是分割线------------------------------------------------------------

fwrite:

从 ptr 指向的内存块写入一个 count 元素数组,每个元素的大小为 Bytes 字节

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
/* fwrite example : write buffer */
#include <stdio.h>

int main ()
{
  FILE * pFile;
  char buffer[] = { 'x' , 'y' , 'z' };
  pFile = fopen ("myfile.bin", "wb");
  fwrite (buffer , sizeof(char), sizeof(buffer), pFile);
  fclose (pFile);
  return 0;
}

创建一个名为 myfile.bin 的文件,并将缓冲区的内容存储到其中。char类型元素是1字节,所以直接用sizeof计算得到的就是数组的大小。

6、Error-handling(错误处理)

clearerr:

清除错误指示器。

void clearerr ( FILE * stream );
#include <stdio.h>

int main() {
  FILE *pFile;
  pFile = fopen("myfile.txt", "r");  // 尝试以只读方式打开文件
  if (pFile == NULL) {
    perror("Error opening file");  // 如果打开文件失败,输出错误信息
  } else {
    fputc('x', pFile);  // 向文件中写入字符 'x'
    if (ferror(pFile)) {
      printf("Error Writing to myfile.txt\n");  // 如果写入文件时发生错误,输出错误信息
      clearerr(pFile);  // 清除文件错误标志
    }
    fgetc(pFile);  // 从文件中读取一个字符
    if (!ferror(pFile)) {
      printf("No errors reading myfile.txt\n");  // 如果读取文件时没有发生错误,输出成功信息
    }
    fclose(pFile);  // 关闭文件
  }
  return 0;
}

程序打开一个名为 myfile.txt 的现有文件进行读取,并导致尝试在其上写入时出现 I/O 错误。使用 clearerr 清除该错误,因此第二次错误检查返回 false。这段代码主要演示了文件操作中的错误处理方式,包括文件打开失败的处理、写入错误的处理、读取错误的处理以及关闭文件。

----------------------------------------------------我是分割线------------------------------------------------------------

feof:

检查是否设置了与关联的文件结束指示符,如果设置了,则返回与零不同的值。

int feof ( FILE * stream );
/* feof example: byte counter */
#include <stdio.h>

int main ()
{
  FILE * pFile;
  int n = 0;
  pFile = fopen ("myfile.txt","rb");
  if (pFile==NULL) perror ("Error opening file");
  else
  {
    while (fgetc(pFile) != EOF) {
      ++n;
    }
    if (feof(pFile)) {
      puts ("End-of-File reached.");
      printf ("Total number of bytes read: %d\n", n);
    }
    else puts ("End-of-File was not reached.");
    fclose (pFile);
  }
  return 0;
}

该程序中打开名为 myfile.txt 的文件,并通过逐个读取所有字符来计算它包含的字符数。程序检查是否已到达文件末尾,如果是,则打印读取的总字节数。

----------------------------------------------------我是分割线------------------------------------------------------------

ferror:

检查是否设置了与关联的错误指示器,如果设置了,则返回与零不同的值。通常由对失败的的先前操作设置,并通过调用 clearerr、rewind 或 freopen 来清除。

ferror 函数用于检查文件流的错误标志。在 C 语言中,文件流通常是通过 FILE 结构指针进行操作的。ferror 函数的返回值表示了文件流的错误标志

/* ferror example: writing error */
#include <stdio.h>
int main ()
{
  FILE * pFile;
  pFile=fopen("myfile.txt","r");
  if (pFile==NULL) perror ("Error opening file");
  else {
    fputc ('x',pFile);
    if (ferror (pFile))
      printf ("Error Writing to myfile.txt\n");
    fclose (pFile);
  }
  return 0;
}

尝试打开一个名为 "myfile.txt" 的文件,并向文件中写入字符 'x'。然后使用 ferror 函数来检查文件流的错误标志,以确定文件操作是否发生了错误。如果发生了错误,则输出相应的错误信息。最后关闭文件并返回 0。

(这段代码的作用是尝试向只读模式打开的文件中写入数据,这是一个错误的操作。因为文件以只读模式打开,所以写入操作会失败ferror 函数会检测到错误,并输出相应的错误信息。)

下面是对该代码的详细讲解:

----------------------------------------------------我是分割线------------------------------------------------------------

perror:

打印错误消息,将 errno 的值解释为错误消息,并将其打印到 stderr(标准错误输出流,通常是控制台),如果参数 str 不是空指针,则打印 str,后跟冒号 (:) 和空格。然后,无论 str 是否为 null 指针,都会打印生成的错误描述,后跟换行符 ('\n')。

perror 应在产生错误后立即调用,否则可能会被调用其他函数覆盖。

void perror ( const char * str );
/* perror example */
#include <stdio.h>

int main ()
{
  FILE * pFile;
  pFile=fopen ("unexist.ent","rb");
  if (pFile==NULL)
    perror ("The following error occurred");
  else
    fclose (pFile);
  return 0;
}

7、Types(类型)

FILE:

FILE 类型是 C 语言中用于表示文件流的结构类型。它通常用于打开、读取、写入和关闭文件。FILE 类型是通过 <stdio.h> 头文件定义的,它提供了一组函数来操作文件流。

以下是一个简单的例子,演示了如何使用 FILE 类型来打开、读取和关闭文件:

#include <stdio.h>

int main() {
  FILE *pFile;
  char buffer[100];

  pFile = fopen("example.txt", "r");  // 以只读模式打开文件
  if (pFile == NULL) {
    perror("Error opening file");
  } else {
    if (fgets(buffer, 100, pFile) != NULL) {  // 从文件中读取内容到 buffer
      printf("Read from file: %s", buffer);
    } else {
      perror("Error reading from file");
    }
    fclose(pFile);  // 关闭文件
  }
  return 0;
}

我们首先声明了一个 FILE 类型的指针 pFile,用于表示文件流。然后使用 fopen 函数以只读模式打开名为 "example.txt" 的文件,如果打开失败则输出错误信息。接着使用 fgets 函数从文件中读取内容到 buffer,并输出到控制台。最后使用 fclose 函数关闭文件。

----------------------------------------------------我是分割线------------------------------------------------------------

fpos_t:

fpos_t 是 C 语言标准库中用来表示文件位置的类型。它通常用于存储文件流的位置,并且可以在文件的定位和操作中使用。

fpos_t 类型的具体实现可能因平台而异,但通常是一个结构或者整数类型。

#include <stdio.h>

int main() {
  FILE *pFile;
  fpos_t position;

  pFile = fopen("example.txt", "r");  // 以只读模式打开文件
  if (pFile == NULL) {
    perror("Error opening file");
  } else {
    fgetpos(pFile, &position);  // 获取当前文件位置
    printf("Current position: %lld\n", (long long)position);

    fseek(pFile, 10, SEEK_SET);  // 设置文件位置到偏移量为 10 的位置
    fgetpos(pFile, &position);  // 获取新的文件位置
    printf("New position: %lld\n", (long long)position);

    fclose(pFile);  // 关闭文件
  }
  return 0;
}

在这个例子中,我们首先声明了一个 fpos_t 类型的变量 position,用于存储文件位置。然后使用 fopen 函数以只读模式打开名为 "example.txt" 的文件,如果打开失败则输出错误信息。接着使用 fgetpos 函数获取当前文件位置,并输出到控制台。然后使用 fseek 函数将文件位置设置到偏移量为 10 的位置,并再次使用 fgetpos 函数获取新的文件位置,并输出到控制台。最后使用 fclose 函数关闭文件。

----------------------------------------------------我是分割线------------------------------------------------------------

size_t:

无符号整形的别名,相当于unsigned int 。

二、小结

在本篇博客中,我们深入探讨了 <stdio.h> 头文件在 C 语言中的重要性以及它所提供的丰富功能。我们首先介绍了该头文件中定义的一些常见函数,例如 fopenfclosefreadfwrite 等,这些函数为我们提供了对文件的打开、关闭、读取和写入等操作。接着我们讨论了 FILE 类型和 fpos_t 类型,它们分别用于表示文件流和文件位置,为我们在文件操作中提供了更多的灵活性和控制。

通过本篇博客的学习,我们不仅对 <stdio.h> 头文件有了更深入的了解,还学会了如何使用它提供的函数和类型来进行文件的操作。文件操作在实际的编程工作中是非常常见的,因此对于 <stdio.h> 头文件的掌握将有助于我们更好地处理文件相关的任务。

希望本篇博客能够帮助读者更好地理解 <stdio.h> 头文件,并在日后的编程工作中能够更加熟练地运用其中提供的函数和类型。关于stdio.h中关于C语言中的宏定义将会在之后的文章进行讲解。如果你有任何关于 C 语言文件操作或者其他编程相关的问题,都可以随时留言交流。感谢阅读!

举报

相关推荐

0 条评论