文章目录

  • ​​一、打开、读写、关闭​​
  • ​​1.1 fopen​​
  • ​​1.2 fclose​​
  • ​​1.3 fwrite​​
  • ​​1.4 fread​​
  • ​​文件读写指针​​
  • ​​二、fseek、feof、ftell​​
  • ​​2.1 实现写读写一行​​
  • ​​2.1.1 写​​
  • ​​2.1.2 读(feof、ftell、rewind)​​
  • ​​2.2 feof经典错误案例​​
  • ​​2.2.1 原理​​
  • ​​2.2.2 判断一个文件是否为空​​
  • ​​2.3 实现将一个文件拷贝给另一个文件​​
  • ​​三、fgetc、fgets、getc、getchar​​
  • ​​四、fputc、fputs、putc、putchar​​
  • ​​五、fprintf(格式化输出)​​
  • ​​五、文件操作(stdin、stdout、stderr)​​
  • ​​六、随机读取数据​​

一、打开、读写、关闭

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 锁定位置(配图)

顺序:先锁定位置,再判断偏移量

嵌入式Linux C(十三)——文件操作(详)_字符串

#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;
}

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