C语言文件操作笔记-1

文件函数说明

此为基础篇文件操作,涉及基础使用函数:
fopen、fclose、fgetc、fgets、getc、fputcs、getchar、putchar、puts、putc、fgetc、ungetc等函数说明。

相关函数说明:

fopen

函数说明: fopen

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:fopen
 * 函数入口:
 *          pathname:打开文件的绝对路径
 *          mode:文件打开模式
 * 函数出口:
 *          FILE:返回该文件的指针(句柄),错误打开返回NULL
 * 函数说明:
 *          按照指定打开方式打开指定路径的文件 
 * ***************************/
FILE *fopen(const char *pathname, const char *mode);

以下内容区分大小写!!!
以下内容区分大小写!!!
以下内容区分大小写!!!

参数说明
r只读打开方式,文件必须存在
r+读写打开方式,文件必须存在,当文件被写入时会在当前流指针处进行写入,如果当前指针流处有字符将会被覆盖。
rb只读打开二进制文本,该文件必须存在
rb+读写打开二进制文本,该文件必须存在
当文件被写入时会在当前流指针处进行写入,如果当前指针流处有字符将会被覆盖。
w以新建只写方式打开,文件已存在内容将会被清空
w+因新建读写方式打开,文件已存在将会被清空
wb以新建写二进制文件方式打开,文件已存在将会被清空
wb+以新建读写二进制文件方式打开,文件已存在将会被清空
a以追加或新建文件方式打开,文件只允许在文件末尾追加
a+以可读、追加或新建文件方式打开,文件只允许在文件末尾追加
ab以追加或新建二进制文件方式打开,件只允许在文件末尾追加
ab+以可读,追加或新建二进制文件方式打开,件只允许在文件末尾追加

fclose

函数说明: fclose

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:fclose
 * 函数入口:
 *             stream 文件流
 * 
 * 函数出口:
 *        如果流成功关闭,则该方法返回零。如果失败,则返回 EOF。
 * 函数说明:
 *       关闭流 stream。刷新所有的缓冲区。
 * ***************************/
int fclose(FILE *stream);

fgetc

函数说明: fgetc

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:fgetc
 * 函数入口:
 *          stream:文件流
 * 函数出口:该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发 
*	读错误,则返回 EOF。
 * 函数说明: 向指定流中读出一个字符
 * ***************************/
 int fgetc(FILE *stream);

fgets

函数说明: fgets

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:fgets
 * 函数入口:
 *          s:存储读出字符串大小的缓冲区
 *          size:读出大小
 *          stream:文件流
 * 函数出口:
 *        如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。
 *        如果发生错误,返回一个空指针。
 * 函数说明: 向指定流中读出一个字串放入到变量s中
 * ***************************/
char *fgets(char *s, int size, FILE *stream);

getc

函数说明: getc

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:getc
 * 函数入口:
            stream:文件流
 * 函数出口:该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。
 * 函数说明:从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符递增移动。
 * 默认只会执行n-1个字符,默认一个字符会在末尾加上\0
 * ***************************/
int getc(FILE *stream);

ungetc

函数说明: ungetc

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:ungetc
 * 函数入口:c:这是要被推入的字符。该字符以其对应的 int 值进行传递。
 *          stream:这是指向 FILE 对象的指针,该 FILE 对象标识了输入流。
 * 函数出口:如果成功,则返回被推入的字符,否则返回 EOF,且流 stream 保持不变。
 * 函数说明:把字符 char(一个无符号字符)推入到指定的流 stream 中,以便它是下一个被读取到的字符。
 * ***************************/
int ungetc(int c, FILE *stream);

fputc

函数说明: fputc

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:fputc
 * 函数入口:c:这是要被写入的字符。该字符以其对应的 int 值进行传递。
 *          stream: 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。
 * 函数出口:如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。
 * 函数说明:把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
 * ***************************/
int fputc(int c, FILE *stream);

fputs

函数说明: fputs

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:fputs
 * 函数入口:str:这是一个数组,包含了要写入的以空字符终止的字符序列。
 *          stream:这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。
 * 函数出口:该函数返回一个非负值,如果发生错误则返回 EOF。
 * 函数说明:把字符串写入到指定的流 stream 中,但不包括空字符。
 * ***************************/
int fputs(const char *s, FILE *stream);

fputs

函数说明: fputs

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:putc
 * 函数入口:c:这是要被写入的字符。该字符以其对应的 int 值进行传递。
 *          stream:这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。
 * 函数出口:该函数以无符号 char 强制转换为 int 的形式返回写入的字符,如果发生错误则返回 EOF。
 * 函数说明:把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。不会自动在文件末尾添加\0
 * ***************************/
int putc(int c, FILE *stream);

fputs

函数说明: fputs

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:ungetc
 * 函数入口:c:这是要被写入的字符。该字符以其对应的 int 值进行传递。
 * 函数出口:该函数以无符号 char 强制转换为 int 的形式返回写入的字符,如果发生错误则返回 EOF。
 * 函数说明:把参数 char 指定的字符(一个无符号字符)写入到标准输出 stdout 中。
 * ***************************/
int putchar(int c);

puts

函数说明: puts

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:puts
 * 函数入口:str:这是要被写入的 C 字符串。
 * 函数出口:如果成功,该函数返回一个非负值为字符串长度(包括末尾的 \0),如果发生错误则返回 EOF。
 * 函数说明:把一个字符串写入到标准输出 stdout,直到空字符,但不包括空字符。换行符会被追加到输出中。
 * ***************************/
int puts(const char *s);

feof

函数说明: feof

/*************头文件*****************/
	#include <stdio.h>
/*****************************
 * 函数名称:feof
 * 函数入口:stream: 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
 * 函数出口:当设置了与流关联的文件结束标识符时,该函数返回一个非零值,否则返回零。
 * 函数说明:测试给定流 stream 的文件结束标识符。
 * ***************************/
int feof(FILE *stream);

示例代码:

说明: 示例中文件名称为test.txt,内部操作数据为以下内容
G P G G A , 092204.999 , 4250.5589 , S , 14718.5084 , E , 2 , 04 , 24.4 , 19.7 , M , , , , 0000 ∗ 1 F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,0000*1F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,00001FGPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M, NULL

示例1:使用fgetc读到文件结束并逐个使用fputc打印

#include "stdio.h"

void main(void)
{
   FILE *fp=fopen("./test.txt","r");
     int c=0;
    while(!feof(fp))
    {
           c=fgetc(fp);
           fputc(c,stdout);
    }
    fclose(fp);
}

运行结果:
G P G G A , 092204.999 , 4250.5589 , S , 14718.5084 , E , 2 , 04 , 24.4 , 19.7 , M , , , , 0000 ∗ 1 F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,0000*1F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,00001FGPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M, NULL

运行结果分析:
文件最后会多读出一次文件结束符
由于feof不会偏移指针,而且当使用feof进行判断文件结束时,是从文件流的0位置开始而不是文件中第一个字符的位置,当先使用feof判断文件结束符 在使用fgetc或者其他读函数(可向下偏移指针流),函数会多进行一次读取,而该次读取将会超过文件。从而读出未知符号。文件结束符不会出现在文件中,而是出现在文件流中。以下改进多读一次代码:

#include "stdio.h"

#define LOG(msg,...) printf("[%s][%d]:"msg"",__FUNCTION__,__LINE__,##__VA_ARGS__)
void main(void)
{
    FILE *fp=fopen("./test.txt","r");//假设文件中写入strlen(123456)+1个字符即7个6+"\0"
    int c=0;
    LOG("%ld\r\n",ftell(fp));//起始位置验证指向流的0位置
    while(1)
    {
      c=fgetc(fp);//每次指向流的位置加一
      if(feof(fp))
      {
        break;
      }
      //fputc(c,stdout);//完美只打印123456
      LOG("%c--%ld\r\n",c,ftell(fp));//将会打印7次(获取但获取当前指针流位置函数)
    }
    fclose(fp);
}

假设文件中有123456\0EOF

运行结果:
使用fputc打印:123456
使用LOG打印:
[main][19]:0
[main][30]:1–1
[main][30]:2–2
[main][30]:3–3
[main][30]:4–4
[main][30]:5–5
[main][30]:6–6
[main][30]:–7
运行结果分析:
可以看见LOG打印了7次而fputc值打印了6次,结果分析fputc
使用fgetc先指向文件流中1位置打印1,再指向文件流中的2位置打印2,依次向下直到遇见文件中\0该内容无法显示fputc展现因此默认为输出为空。

LOG分析,当fgetc指向文件流中1位置打印1此时使用ftell获取的文件流位置为1,依次类推,当文件流位置指向\0时文件流为7,而此时%c无法打印\0,此时再使用fgetc将会指向文件外内容,从而文件流中生成EOF,造成退出。
同理分析以上内容其实都是打印了7次,只是fputc没有凸显\0那次打印。
将LOG修改为此语句printf(“%c”,c);结果同fputc

以上方法完美修复了案例一种使用feof多读出一次的情况,该案例原始就是写入例如strlen(123456)+1(使用strlen+1将会将字符串结束符写入文件),因此读出了7次,想要修复该BUG只需要,使用先偏移指针,再使用feof。

示例2:fgets读取文件字符串

#include "stdio.h"

void main(void)
{
  FILE *fp=fopen("./test.txt","r");
  char stdbuf[6]={0};
  fgets(stdbuf,5,fp);//读取到n-1、末尾或者错误会停止(只会读出5-1个字符)
  fputs(stdbuf,stdout);
  fputc('\n',stdout);
  fclose(fp);
}

运行结果:
$GPG
(换行符\n)

示例3:getc位置递增演示

#include "stdio.h"

 void main(void)
{
      char stdbuf[6]={0};
      FILE *fp=fopen("./test.txt","r");
      int ch=getc(fp);
      fputc(ch,stdout);
      fputc('\n',stdout);// 第一次读出
      ch=getc(fp);
      fputc(ch,stdout);
      fputc('\n',stdout);//第二次读出
      ch=getc(fp);
      fputc(ch,stdout);
      fputc('\n',stdout);//第三次读出
      fclose(fp);
}

运行结果:
$
G
P
(换行符\n)

示例4:fputs测试

#include "stdio.h"

void main(void)
{
    char buf[1024]={0};
    FILE *fp=fopen("./test.txt","r"); 
    fgets(buf,1024,fp);//虽然读到的是1024个字节但是当遇到文件结束符将会停止
    fputs(buf,stdout);
    fclose(fp);
}

运行结果:
G P G G A , 092204.999 , 4250.5589 , S , 14718.5084 , E , 2 , 04 , 24.4 , 19.7 , M , , , , 0000 ∗ 1 F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,0000*1F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,00001FGPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M, NULL

示例5:getchar与putchar

#include "stdio.h"

void main(void)
{
    char buf[1024]={0};
    int ch=getchar();
    ch=putchar(ch);
    putchar('\n');
    printf("%c\r\n",ch);
}

运行结果:(以在终端输入 5为示例)
5
5
5

示例6:puts与putc

#include "stdio.h"

void main(void)
{
     int a='a';
     putc(a,stdout);//默认以int强转字符输出
     putc('\n',stdout);//打印\n
     puts("123456");//默认输出到标准输出流
}

运行结果:
a
123456

示例7:fgetc

#include "stdio.h"

void main(void)
{
    
     int ch=getc(stdin);
     printf("%c\r\n",ch);
}

运行结果:(以终端输入5位例)
5
5

示例8:ungetc

#include "stdio.h"

int main ()
{
   FILE *fp;
   int c;
   char buffer [256];
   fp = fopen("test.txt", "r");
   if( fp == NULL )
   {
      perror("打开文件时发生错误");
      return(-1);
   }
   while(1)
   {
        c = getc (fp);
        if(feof(fp))
        {
        break;
        }
        if( c == '$' )
        {
        	 ungetc ('+', fp);
        }
        else
        {
        	 ngetc(c, fp);
        }
        fgets(buffer, 255, fp);
        fputs(buffer, stdout);
   }
   return(0);
}

运行结果:
+GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,0000*1F$GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M, NULL
结果分析:
只会将流中的字符替换,不会修改文件中的字符。

示例9:r+是追加还是新建?

#include "stdio.h"

int main ()
{
    FILE *fp;
    int c;
    char buffer [256];
    fp = fopen("test.txt", "r+");
    fputs("123456",fp);
    fclose(fp);//将流指向的位置偏移回来
    fp = fopen("test.txt", "r");
    fgets(buffer,255,fp);
    fputs(buffer,stdout);
    fclose(fp);
    return(0);
}

运行结果:
123456,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,0000*1F$GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M, NULL
运行结果分析:
新写入的会进行覆盖式写入 如果不覆盖需要遍历到文件尾的位置进行写入。

示例10:fgets遇\0结束?

#include "stdio.h"

int main ()
{
    FILE *fp;
    int a=0;
    int c=0;
    char buf[]="$GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,0000*1F$GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,, NULL";
    char buffer [1024];
    fp = fopen("test.txt", "w+");//新建文件
    fwrite(buf,strlen(buf)+1,1,fp);//注意使用strlen+1将会在文件尾默认写入\0
    fclose(fp);//关闭将流的指针复位
    fp = fopen("test.txt", "a+");//在文件尾追加如123456
    fputs("123456",fp);
    fclose(fp);//复位流的位置
    fp = fopen("test.txt", "r");
    while(1)//使用fgetc读
    {
    	c=fgetc(fp);
    	if(feof(fp))
    	{
        break;
    	}
    a++;
    fputc(c,stdout);
    }
    printf("\r\n");
    printf("%d\r\n",a);//验证读大字节大小
    fclose(fp);//复位流指针
    fp = fopen("test.txt", "r");//使用fgets读
    fgets(buffer,1024,fp);
    fputs(buffer,stdout);
    fclose(fp);
    return(0);
}

运行结果:
G P G G A , 092204.999 , 4250.5589 , S , 14718.5084 , E , 2 , 04 , 24.4 , 19.7 , M , , , , 0000 ∗ 1 F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,0000*1F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,00001FGPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M, NULL123456
145
G P G G A , 092204.999 , 4250.5589 , S , 14718.5084 , E , 2 , 04 , 24.4 , 19.7 , M , , , , 0000 ∗ 1 F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,0000*1F GPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M,,,,00001FGPGGA,092204.999,4250.5589,S,14718.5084,E,2,04,24.4,19.7,M, NULL
运行结果分析:
可以看到使用fgetc打印了出了123456,而使用fgets没有打印出123456,原因就是fgets遇到\0将不在打印。

示例11:fgets从标准输入流写入时不足设置长度将会读入回车

#include "stdio.h"

int main ()
{
    char a[10];
    for (int i = 0; i < 10; ++i)
    a[i] = '1';
    fgets(a, 5, stdin);
    for (int i = 0; i < 10; ++i)
    printf(":[%d]%c:\n", i,a[i]);
    return(0);
}

运行结果:
当从终端输入55555时效果
:[0]5:
:[1]5:
:[2]5:
:[3]5:
:[4]:
:[5]1:
:[6]1:
:[7]1:
:[8]1:
:[9]1:
当从终端输入5时效果:
5
:[0]5:
:[1]
:
:[2]:
:[3]1:
:[4]1:
:[5]1:
:[6]1:
:[7]1:
:[8]1:
:[9]1:
运行结果分析:
此例中fgets中要求获取5个字符大小,到时当输入5个字符时只会获取4个另一会添加一个\0.
当输入字符数小于n-1时将会将输入时的回车符读入。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值