嵌入式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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理