嵌入式Linux C(十三)——文件操作(详)

一、打开、读写、关闭

1.1 fopen

文件使用方式含义如果指定的文件不存在
r(只读)打开一个已经存在的文件出错
w(只写)打开一个个文本文件建立新文件
a(追加)向文本文件末尾添加数据出错
r+(读写)为了读写,打开一个文本文件出错
w+(读写)为了读写,建立一个新的文本文件建立新文件/将源文件覆盖(清空)
a+(读写)为了读写,打开一个文本文件建立新文件

一般用a+

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

int main(int argc, char const *argv[])
{
    FILE *fp;

    //fp = fopen("a.txt","w+");
    fp = fopen(argv[1],"a+");


    if (NULL == fp)
    {
        printf("file a.txt error!\n");
        exit(1);
    }
    return 0;
}

b可以以二进制打开文件,不加为字符打开

1.2 fclose

FILE *fp;
 fp = fopen(argv[1],"a+");
 fclose(fp);

1.3 fwrite

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
const void *ptr:要写入的数据指针
size_t size:每次写size字节
size_t nmemb:总共写nmemb次
FILE *stream:所写入的文件
返回值:nmemb(写了多少次)
出错是0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    FILE *fp;

    //fp = fopen("a.txt","w+");
    fp = fopen(argv[1],"a+");
    //fp = fopen(argv[1],"r");


    if (NULL == fp)
    {
        printf("file a.txt error!\n");
        exit(1);
    }

    char buffer[1024] = "hello world";

    int ret = fwrite(buffer,1,strlen(buffer),fp);
    
    printf("ret = %d\n",ret);

    return 0;
}

1.4 fread

size_t fread(void *ptr, size_t size, size_t nmemb,FILE *stream);
void *ptr:要写入的数据指针
size_t size:每次读size字节
size_t nmemb:总共读nmemb次
FILE *stream:所写入的文件
返回值:nmemb(读了多少次)
出错是0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
   FILE *fp;

   //fp = fopen("a.txt","w+");
   fp = fopen(argv[1],"a+");


   if (NULL == fp)
   {
       printf("file a.txt error!\n");
       exit(1);
   }

   char buffer[1024] = "hello world";

   int ret = fwrite(buffer,1,strlen(buffer),fp);
   
   printf("ret = %d\n",ret);

   memset(buffer,0,sizeof(buffer));

   ret = fread(buffer,1,ret,fp);

   buffer[ret] = '\0';

   printf("read buffer = %s\n",buffer);

   return 0;
}
//读不出来,是因为文件读写位置指针指向末尾

文件读写指针

文件使用方式文件读写指针位置
r首位
r+首位
w首位
w+首位
a末尾
a+末尾

二、fseek、feof、ftell

int fseek(FILE *stream, long offset, int whence);

FILE *stream 目标文件
long offset 偏移量(正数是后移,负数是前移)
int whence 锁定位置(配图)
顺序:先锁定位置,再判断偏移量
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    FILE *fp;

    //fp = fopen("a.txt","w+");
    fp = fopen(argv[1],"a+");


    if (NULL == fp)
    {
        printf("file a.txt error!\n");
        exit(1);
    }

    char buffer[1024] = "hello world";

    int ret = fwrite(buffer,1,strlen(buffer),fp);

    if(0 == ret)
    {
        printf("fwrite a.txt error!\n");
        exit(1);
    }
    
    printf("ret = %d\n",ret);

    ret = fseek(fp,0,SEEK_SET);

    if(-1 == ret)
    {
        printf("fseek a.txt error!\n");
        exit(1);
    }

    memset(buffer,0,sizeof(buffer));

    ret = fread(buffer,1,ret,fp);

    if(0 == ret)
    {
        printf("fread a.txt error!\n");
        exit(1);
    }

    buffer[ret] = '\0';

    printf("read buffer = %s\n",buffer);

    return 0;
}

2.1 实现写读写一行

2.1.1 写

fwrite("\n",1,1,fp);

2.1.2 读(feof、ftell、rewind)

文档结尾有个隐藏字符EOF
int feof(FILE *stream);
文件结束:返回非0值;文件未结束:返回0值
ftell:用来得到文件指针离文件开头的偏移量
long ftell(FILE *stream);
rewind()用于文件指针移动到文件的开头,当移动成功时
void rewind(FILE *stream);

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

int main(int argc, char const *argv[])
{
    FILE *fp;

    //fp = fopen("a.txt","w+");
    fp = fopen(argv[1], "a+");

    if (NULL == fp)
    {
        printf("file a.txt error!\n");
        exit(1);
    }

    char buffer[1024] = "hello world";

    int ret = fwrite(buffer, 1, strlen(buffer), fp);
    fwrite("\n", 1, 1, fp);
    if (0 == ret)
    {
        printf("fwrite a.txt error!\n");
        exit(1);
    }

    printf("ret = %d\n", ret);

    ret = fseek(fp, 0, SEEK_SET);

    if (-1 == ret)
    {
        printf("fseek a.txt error!\n");
        exit(1);
    }
    memset(buffer,0,sizeof(buffer));
    char temp;
    int i = 0;

    while (!feof(fp))
    {
        if(fread(&temp, 1, 1, fp) == -1)
        {
            printf("file fread error!\n");
        }

        buffer[i] = temp;
        i++;
    }


#if 0
    ret = fread(buffer,1,ret,fp);

    if(0 == ret)
    {
        printf("fread a.txt error!\n");
        exit(1);
    }
#endif
    buffer[i] = '\0';

    printf("read buffer = %s\n",buffer);

    fclose(fp);

    return 0;
}

2.2 feof经典错误案例

2.2.1 原理

原理:站在光标所在位置,向后面看看有没有字符,如果有,返回0;如果没有,返回非0。它并不会读取相关信息,只会查看光标后是否有内容
功能:检测文件结束符EOF

2.2.2 判断一个文件是否为空

#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    fp = fopen(argv[1], "a+");
    
#if 0
    if (feof(fp) == 0)
    {
        printf("file is empty\n");
    }
#endif
    if (feof(fp) != 0)
    {
        printf("file is empty\n");
    }

    fclose(fp);

    return 0;
}

现象:feof并不能判断空文件,返回为0
原因:当文件内部的位置指针指向文件结束时,并不会立即设置FILE结构中的文件结束标识,只有再执行一次读文件操作,才会设置结束标志,此后调用feof()才会返回为真。

解决

#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *p;
    getc(p);
    if (feof(p))
    {
        printf("file is empty.\n");
    }
    else
    {
        rewind(p);//将光标跳回到文件开头
        int a;
        fscanf(p,"%d",&a);
        printf("%d",a);
    }
    
    return 0;
}
//例如,有一个文件指针fp,文件中有字符串“hello world”:
int c=0;
while( !feof(fp) )
{
    int c=fgetc(fp);
    printf("%c: %x \n", c, c);
}
//上面的代码除了输出 hello 外,还会输出一个结束字符EOF(EOF是fgetc函数的返回值,
//并不是文件中存在EOF)。其原因就是当内部位置指针指向结尾时,
//还要执行一次读操作,文件结束标识才会被设置。

//修改
int c; 
c=fgetc(fp);     
while( !feof(fp) ) 
{    
    printf("%c: %x \n", c, c); 
    c=fgetc(fp); 
}
//上面的代码只输出“hello”不输出文件结束符EOF。
//当文件内部位置指针指向结束位置时,先执行一次读操作,
//设置文件结束标识,while循环立即结束。

参考网站:C语言feof()函数:检查流上文件的结束标识(是否读到文件结尾)

2.3 实现将一个文件拷贝给另一个文件

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

void isOK(FILE *fp, char *filename)
{
    if (fp == NULL)
    {
        printf("%s open error!\n", filename);
        exit(1);
    }
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("Please input file name!\n");
        exit(1);
    }

    FILE *to_fp;
    FILE *from_fp;

    char buffer[1024] = {0};

    from_fp = fopen(argv[1], "r");

    isOK(from_fp, argv[1]);

    to_fp = fopen(argv[2], "a+");

    isOK(to_fp, argv[2]);

    fseek(to_fp, 0, SEEK_SET); //rewind(to_fp);

    fseek(from_fp, 0, SEEK_END);

    int w_len;
    int file_size = ftell(from_fp);

    fseek(from_fp, 0, SEEK_SET);

    while (!feof(from_fp))
    {
        memset(buffer, 0, sizeof(buffer));
        fread(buffer, 1, sizeof(buffer) - 1, from_fp);
        w_len = fwrite(buffer, 1, strlen(buffer), to_fp);
        //printf("%s\n", buffer);

        file_size = file_size - w_len;
        
        if (file_size < 0)
        {
            break;
        }
        
    }

    return 0;
}

三、fgetc、fgets、getc、getchar

getchar:从终端上获取一个字符
fgetc

头文件:#include <stdio,h>

原型:int fgetc(FILE *stream)

功能:从文件中获取一个字符

参数:stream 目标文件指针

返回值:该字符所对应的ASCII码,若返回`EOF`则表示到了文件尾

getc

getc()和fgetc(),作用相同,但是getc()是宏定义,非真正的函数调用


char temp;
while ((temp = fgetc(from_fp)) != EOF)
	{
		fputc(temp, to_fp)
	}
    return 0;
}

fgets

头文件:#include <stdio,h>

原型:char *fgets(char *s, int size, FILE *stream)

功能:
	 读取stream一行,存储到s中。当读取 (size-1) 个字符时,
	 或者读取到换行符时,或者到达文件末尾时,它会停止,并加上`\0`
参数:
	s 这是指向一个字符数组的指针,该数组存储了要读取的字符串
	size 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
	stream 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。
返回值:
	如果成功,该函数返回相同的 s 指针。失败则返回`NULL`。

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

	fgets(buffer, sizeof(buffer), from_fp);
	buffer[strlen(buffer) - 1] = '\0';  //把读取到的`\n`给去除
	printf("%s\n", buffer);
	//打印:#include <stdio.h>

四、fputc、fputs、putc、putchar

putchar:从终端上输出一个字符
fputc

头文件:#include <stdio,h>

原型:int fputc(int c, FILE *stream)

功能:向stream写入一个字符c

参数:
	c 你要输入的字符(int 是其ASCII)
	stream 你要输入的文件指针
	
返回值:如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF

char temp;
while ((temp = fgetc(from_fp)) != EOF)
	{
		fputc(temp, to_fp)
	}
    return 0;
}

putc

putc()和fputc(),作用相同,但是putc()是宏定义,非真正的函数调用

fputs

头文件:#include <stdio,h>

原型:int *fputs(const char *s, FILE *stream)

功能:把字符串写入到指定的流 stream 中,但不包括``\0。

参数:
	s 要写入的字符串
	stream 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。
返回值:
	该函数返回一个非负值,如果发生错误则返回 EOF

	while (fgets(buffer, sizeof(buffer), from_fp != NULL))
	{
		fputs(buffer, to_fp)
		memset(buffer, 0, sizeof(buffer));
	}

五、fprintf(格式化输出)

文件里面没格式,需要自己去定义

头文件:#include <stdio,h>

原型:int fprintf(FILE *stream, const char *format...)

功能:会根据参数format字符串来转换并格式化数据,然后将结果输出到参数stream指定的文件中,知道字符串结束(\0)为止

参数:
	stream 目标文件指针
	format 这是 C 字符串,包含了要被写入到流 stream 中的文本。

返回值:如果成功,则返回写入的字符总数,否则返回一个负数。

fprintf详见:C 库函数 - fprintf

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int num = 5;
    char name[20] = "zhangsan";
    int age = 16;

    FILE *fp = fopen(argv[1], "a+");

    fprintf(fp, "%d:%s:%d\n", num, name, age); //sprintf

    // fwrite(&num, 1, sizeof(num), fp);

    // fseek(fp, 0, SEEK_SET);

    // int temp;

    // fread(&temp, 1, sizeof(temp), fp);

    fclose(fp);

    return 0;
}

五、文件操作(stdin、stdout、stderr)

文件指针:
stdin(键盘)
stdout(终端)
stderr(终端)

char buffer[1024];

fgets(buffer,sizeof(buffer),stdin); //键盘上读取数据
buffer[strlen(buffer) - 1] = '\0';
fputs(buffer,stdout);
打印错误信息或者调试信息时,用stderr
打印正常信息时,用stdout

六、随机读取数据

二进制读取文件

#include <stdio.h>

struct node
{
    int num;
    char name[20];
    int age;
};


int main(int argc, char const *argv[])
{
    FILE *fp = fopen(argv[1], "ab+");

    if (NULL == fp)
    {
        printf("error!");
        exit(1)
    }
    
    struct node p1 = {.num = 1, .name = "zhangsan", .age = 16};
    struct node p2 = {.num = 2, .name = "zhangsi", .age = 17};
    struct node p3 = {.num = 3, .name = "zhangwu", .age = 18};

    fwrite(&p1, 1, sizeof(p1),fp);
    fwrite(&p2, 1, sizeof(p1),fp);
    fwrite(&p3, 1, sizeof(p1),fp);

    fseek(fp, 0, SEEK_SET)

    fseek(fp, sizeof(struct node), SEEK_SET);

    struct node temp;

    fread(&temp, 1, sizeof(struct node),fp);

    printf("num = %d, name = %s, age = %d\n", temp.num, temp.name, temp.age);

    fclose(fp);

    return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周末不下雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值