c语言文件操作(fgetc,fputc,fgets,fputs,fprintf,fscanf,feof,fcntl)

一、fgetc函数

1.功能描述

C 库函数 int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。

2.参数

  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流。

3.函数原型

int fgetc(FILE *stream)
//该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。

 

实例

下面的实例演示了 fgetc() 函数的用法。

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;
   int n = 0;
  
   fp = fopen("file.txt","r");
   if(fp == NULL) 
   {
      perror("打开文件时发生错误");
      return(-1);
   }
   do
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }while(1);

   fclose(fp);
   return(0);
}

 

假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:

We are in 2014

让我们编译并运行上面的程序,这将产生以下结果:

We are in 2014

 

二、fputc函数

1.功能描述

C 库函数 int fputc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。

2.参数

  • char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。

3.函数原型

int fputc(int char, FILE *stream)
//如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。

 

实例

#include <stdio.h>
 
int main ()
{
   FILE *fp;
   int ch;
 
   fp = fopen("file.txt", "w+");
   for( ch = 33 ; ch <= 100; ch++ )
   {
      fputc(ch, fp);
   }
   fclose(fp);
 
   return(0);
}

 

让我们编译并运行上面的程序,这将在当前目录中创建文件 file.txt,它的内容如下:

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcd

三、fgets函数

1.功能描述

C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

2.参数

  • str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
  • n -- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。

3.函数原型

char *fgets(char *str, int n, FILE *stream)
/*如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。

如果发生错误,返回一个空指针。*/

 

实例

下面的实例演示了 fgets() 函数的用法。

#include <stdio.h>

int main()
{
   FILE *fp;
   char str[60];

   /* 打开用于读取的文件 */
   fp = fopen("file.txt" , "r");
   if(fp == NULL) {
      perror("打开文件时发生错误");
      return(-1);
   }
   if( fgets (str, 60, fp)!=NULL ) {
      /* 向标准输出 stdout 写入内容 */
      puts(str);
   }
   fclose(fp);
   
   return(0);
}

 

假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:

We are in 2014

 

让我们编译并运行上面的程序,这将产生以下结果:

We are in 2014

 

四、fputs函数

1.功能描述

C 库函数 int fputs(const char *str, FILE *stream) 把字符串写入到指定的流 stream 中,但不包括空字符。

2.参数

  • str -- 这是一个数组,包含了要写入的以空字符终止的字符序列。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。

3.函数原型

int fputs(const char *str, FILE *stream)
//返回值:该函数返回一个非负值,如果发生错误则返回 EOF(-1)。

 

 实例

下面的实例演示了 fgets() 函数的用法。

#include <stdio.h>

int main()
{
   FILE *fp;
   char str[60];

   /* 打开用于读取的文件 */
   fp = fopen("file.txt" , "r");
   if(fp == NULL) {
      perror("打开文件时发生错误");
      return(-1);
   }
   if( fgets (str, 60, fp)!=NULL ) {
      /* 向标准输出 stdout 写入内容 */
      puts(str);
   }
   fclose(fp);
   
   return(0);
}

 

假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:

We are in 2014

让我们编译并运行上面的程序,这将产生以下结果:

We are in 2014

五、fprintf函数

1.功能描述

C 库函数 int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中。

2.参数

specifier(说明符)输出
c字符
d 或 i有符号十进制整数
e使用 e 字符的科学科学记数法(尾数和指数)
E使用 E 字符的科学科学记数法(尾数和指数)
f十进制浮点数
g自动选择 %e 或 %f 中合适的表示法
G自动选择 %E 或 %f 中合适的表示法
o有符号八进制
s字符的字符串
u无符号十进制整数
x无符号十六进制整数
X无符号十六进制整数(大写字母)
p指针地址
n无输出
%字符

 

  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • format -- 这是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:
  • 附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

3.函数原型

int fprintf(FILE *stream, const char *format, ...)
//如果成功,则返回写入的字符总数,否则返回一个负数。

 

实例

下面的实例演示了 fprintf() 函数的用法。

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

int main()
{
   FILE * fp;

   fp = fopen ("file.txt", "w+");
   fprintf(fp, "%s %s %s %d", "We", "are", "in", 2014);
   
   fclose(fp);
   
   return(0);
}

 

让我们编译并运行上面的程序,这将创建文件 file.txt,它的内容如下:

We are in 2014

现在让我们使用下面的程序查看上面文件的内容:

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;

   fp = fopen("file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}

 

六、fscanf函数

1.功能描述

C 库函数 int fscanf(FILE *stream, const char *format, ...) 从流 stream 读取格式化输入。

2.参数

 

参数描述
*这是一个可选的星号,表示数据是从流 stream 中读取的,但是可以被忽视,即它不存储在对应的参数中。
width这指定了在当前读取操作中读取的最大字符数。
modifiers为对应的附加参数所指向的数据指定一个不同于整型(针对 d、i 和 n)、无符号整型(针对 o、u 和 x)或浮点型(针对 e、f 和 g)的大小: h :短整型(针对 d、i 和 n),或无符号短整型(针对 o、u 和 x) l :长整型(针对 d、i 和 n),或无符号长整型(针对 o、u 和 x),或双精度型(针对 e、f 和 g) L :长双精度型(针对 e、f 和 g)
type一个字符,指定了要被读取的数据类型以及数据读取方式。具体参见下一个表格。

fscanf 类型说明符:

类型合格的输入参数的类型
c单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。char *
d十进制整数:数字前面的 + 或 - 号是可选的。int *
e,E,f,g,G浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4float *
o八进制整数。int *
s字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。char *
u无符号的十进制整数。unsigned int *
x,X十六进制整数。int *

 

  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • format -- 这是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符 和 format 说明符
    format 说明符形式为 [=%[*][width][modifiers]type=],具体讲解如下:
  • 附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

3.函数原型

int fscanf(FILE *stream, const char *format, ...)
//如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。

实例

下面的实例演示了 fscanf() 函数的用法。

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


int main()
{
   char str1[10], str2[10], str3[10];
   int year;
   FILE * fp;

   fp = fopen ("file.txt", "w+");
   fputs("We are in 2014", fp);
   
   rewind(fp);
   fscanf(fp, "%s %s %s %d", str1, str2, str3, &year);
   
   printf("Read String1 |%s|\n", str1 );
   printf("Read String2 |%s|\n", str2 );
   printf("Read String3 |%s|\n", str3 );
   printf("Read Integer |%d|\n", year );

   fclose(fp);
   
   return(0);
}

让我们编译并运行上面的程序,这将产生以下结果:

Read String1 |We|
Read String2 |are|
Read String3 |in|
Read Integer |2014|

 

七、feof()函数是什么?

feof()是检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0

一般在文件操作,中经常使用feof()判断文件是否结束。


feof()的经典错误

根据这个函数的定义,一般大家都是这样使用的,但是这样使用,文件中无论是否有内容,都会被判断为“文件不为空”。

#include<stdio.h>
int main(void)
{
    FILE *p;
    p = fopen("open.txt", "r");
    if (feof(p))
    {
        printf("文件为空。");
    }
    else
    {
        printf("文件不为空。");
    }
    return 0;
 }

feof()的原理

1.EOF

EOF是一个计算机术语,为End Of File的缩写,在操作系统中表示资料源无更多的资料可读取。资料源通常称为档案或串流。通常在文本的最后存在此字符表示资料结束。

这个定义的意思是,文档的结尾都有一个隐藏字符”EOF”,当程序读取它的时候,就会知道文件已经到达结尾。通常使用while循环加EOF判断作为读取结束的标志。

EOF 的值通常为 -1,但它依系统有所不同。

2.feof()

  • feof()的原理:
    • feof()函数,并不是通过读取到文件的EOF来评判,这个文件是否为空。
    • 对feof()来说,它的工作原理是,站在光标所在位置,向后看看还有没有字符。如果有,返回0;如果没有,返回非0。它并不会读取相关信息,只是查看光标后是否还有内容。
  • 直接使用时的错误分析:
    • 对于一个空文件来说,当程序打开它的时候,它的光标会停在文件的开头,但是由于文件里什么内容都没有存(但是EOF是存在的),即整个文件就存贮了一个EOF。当程序打开文件,并直接调用feof()时,这个函数就会站在光标的位置向后张望,结果就看见了EOF,然后就当然返回0了。

如何正确使用

既然我们明白了原理,那么如何正确的使用它呢?

#include<stdio.h>
int main(void)
{
    FILE *p;
    p = fopen("open.txt", "r");
    getc(p);
    if (feof(p))
    {
        printf("文件为空。");
    }
    else
    {
        rewind(p);//将光标跳回到文件开头
        int a;
        fscanf(p,"%d",&a);
        printf("%d", a);
    }
    return 0;
 }

分析:

  • 对于文件来说,无论是空文件,还是存有信息的文件,当文件被打开,光标处于默认的开头时,光标后都有信息,这时候调用feof()来查看光标后是否还有内容,就没意义。
  • 所以我们需要从相同中找不同,先使用getc(),从文件中读取一个字符,让光标向后移动一个字符。这时空文件的光标就已经移动到EOF的后面,这时使用feof()就会返回1了。这才是feof()的正确用法。
  • 但是要注意,一定要将光标回到文件的开头,因为之前判断文件是否为空时,将光标向前移动了一位,必须要将光标恢复到开头,这样才能保证文件的正常读取。

 

八、fcntl函数

1.功能描述

根据文件描述词来操作文件的特性。

文件控制函数          fcntl -- file control

2.参数

 

            fcntl()针对(文件)描述符提供控制.参数fd是被参数cmd操作(如下面的描述)的描述符.            

   针对cmd的值,fcntl能够接受第三个参数(arg)

            fcntl函数有5种功能:

      1.复制一个现有的描述符(cmd=F_DUPFD).

           2.获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).

                3.获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).

                4.获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).

               5.获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).

          cmd 选项:

                         F_DUPFD      返回一个如下描述的(文件)描述符:                            

                (1)最小的大于或等于arg的一个可用的描述符                          

             (2)与原始操作符一样的某对象的引用               

                   (3)如果对象是文件(file)的话,返回一个新的描述符,这个描述符与arg共享相同的偏移量(offset)                    

           (4)相同的访问模式(读,写或读/写)                          

           (5)相同的文件状态标志(如:两个文件描述符共享相同的状态标志)                            

               (6)与新的文件描述符结合在一起的close-on-exec标志被设置成交叉式访问execve(2)的系统调用                     

             F_GETFD     取得与文件描述符fd联合close-on-exec标志,类似FD_CLOEXEC.如果返回值和FD_CLOEXEC进行与运算结果是0的话,文件保持交叉式访问exec(),否则如果通过exec运行的话,文件将被关闭(arg被忽略)                  

             F_SETFD     设置close-on-exec旗标。该旗标以参数arg的FD_CLOEXEC位决定。                   

             F_GETFL     取得fd的文件状态标志,如同下面的描述一样(arg被忽略)                    

             F_SETFL     设置给arg描述符状态标志,可以更改的几个标志是:O_APPEND, O_NONBLOCK,O_SYNC和O_ASYNC。
             F_GETOWN 取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回成负值(arg被忽略)                    

             F_SETOWN 设置将接收SIGIO和SIGURG信号的进程id或进程组id,进程组id通过提供负值的arg来说明,否则,arg将被认为是进程id
              

命令字(cmd)F_GETFL和F_SETFL的标志如下面的描述:            

             O_NONBLOCK        非阻塞I/O;如果read(2)调用没有可读取的数据,或者如果write(2)操作将阻塞,read或write调用返回-1和EAGAIN错误                            O_APPEND             强制每次写(write)操作都添加在文件大的末尾,相当于open(2)的O_APPEND标志         

             O_DIRECT             最小化或去掉reading和writing的缓存影响.系统将企图避免缓存你的读或写的数据.

                             如果不能够避免缓存,那么它将最小化已经被缓存了的数 据造成的影响.如果这个标志用的不够好,将大大的降低性能                      

             O_ASYNC              当I/O可用的时候,允许SIGIO信号发送到进程组,例如:当有数据可以读的时候

 注意:      在修改文件描述符标志或文件状态标志时必须谨慎,先要取得现在的标志值,然后按照希望修改它,最后设置新标志值。不能只是执行F_SETFD或F_SETFL命令,这样会关闭以前设置的标志位。

3.函数原型

 

//头文件:

#include <unistd.h>

#include <fcntl.h>

//函数原型:          

int fcntl(int fd, int cmd);

int fcntl(int fd, int cmd, long arg);         

int fcntl(int fd, int cmd, struct flock *lock);

/*fcntl的返回值:  与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。下列三个命令有特定返回值:F_DUPFD,F_GETFD,F_GETFL以及F_GETOWN。第一个返回新的文件描述符,第二个返回相应标志,最后一个返回一个正的进程ID或负的进程组ID。*/

 

 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值