当前位置:首页 > 编程笔记 > 正文
已解决

C文件操作

来自网友在路上 165865提问 提问时间:2023-10-31 06:21:49阅读次数: 65

最佳答案 问答题库658位专家为你答疑解惑

目录

1. 什么是文件

2. 为什么要有文件

3. 文件名

4. 文件类型

5. 文件指针

6. 文件的打开和关闭

7. 文件的顺序读写

7.1. fgetc 

7.2. fputc

7.3. fgets

7.4. fputs

7.5. fscanf

7.6. fprintf

7.8. sscanf

7.9. sprintf

7.9. fread

7.10. fwrite

8. 文件的随机读写

8.1. fseek

8.2. ftell

8.3. rewind

9. 文件结束的判定


1. 什么是文件

简单讲,磁盘上的文件是文件。它是一组有序的字节序列,用于保存和组织信息。在计算机系统中,文件可以包含各种类型的数据,例如文本、图像、音频、视频等。文件是计算机中的一个抽象概念,它在硬盘实际以二进制数据的形式存储。

而在程序设计中,我们一般谈的文件分为两种:程序文件、数据文件(我们接下来主要讨论的就是数据文件)

程序文件:包括C源文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

数据文件:文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件

2. 为什么要有文件

我们知道,内存实际上是一种带电存储的存储介质,也就是说只有通电时,内存才能存储数据。但是事实上,有时候我们也需要不带电的存储方式:文件可以将数据永久保存在计算机的存储介质中,以便于后续使用和处理。在没有文件的情况下,数据只能暂时存储在计算机内存中,一旦计算机断电或重启,数据就会丢失。

3. 文件名

文件名是用来标识和区分不同文件的一串字符或字符串。

文件名包含三部分:文件路径 + 文件名主干 + 文件后缀,例如:E:\vs2013\Code\Code_2023_10\Project_10_31\Project_10_31\test.c

4. 文件类型

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。

文本文件是一种存储纯文本数据的文件类型。它包含了由ASCII码或Unicode编码表示的文本字符,用来表示文字的内容,而不包含任何格式、样式或图像等其他元素。

文本文件是由连续的字符构成,每个字符都有一个对应的编码值。常见的编码方式包括ASCII、UTF-8和UTF-16等。其中,ASCII编码适用于英语和其他拉丁字母字符,而UTF-8和UTF-16编码则可以包含更广泛的字符集,包括多种语言的文字、符号和表情等。

常见的文本文件格式包括.txt(纯文本文件)、.csv(逗号分隔值文件,常用于电子表格数据)、.html(超文本标记语言文件,用于网页)、.json(JavaScript对象表示法文件,用于数据交换)、.xml(可扩展标记语言文件,用于数据描述)等。这些文本文件可以通过文本编辑器或特定的软件程序进行打开、编辑和保存。

二进制文件是一种存储任意数据的文件类型,它包含了以二进制形式表示的数据,与文本文件不同,不直接使用可识别的字符集或编码来存储数据

二进制文件中的数据以字节为单位,在计算机中以二进制数形式表示。这意味着它可以存储任意的数字、文本、图像、音频、视频或其他形式的数据。二进制文件中的数据不遵循特定的结构或格式,而是取决于数据的用途和创建方式。

与文本文件相比,二进制文件的优点是可以存储和处理更广泛的数据类型和格式。例如,图像文件(如.jpg、.png)和音频文件(如.mp3、.wav)通常都是以二进制形式存储的,因为它们包含了大量的非文本数据。

二进制文件通常需要特定的软件程序或应用程序来打开、读取和解析。这些软件程序可以根据特定的文件格式和数据结构来处理和解释数据。例如,图像编辑软件可以解析二进制图像文件并显示图像内容,音频播放器可以解析二进制音频文件并播放音频。

需要注意的是,二进制文件的内容通常不直接可读或可编辑。因为它们没有经过字符编码,所以不能直接以文本形式打开和编辑。如果尝试用文本编辑器打开二进制文件,将看到一堆乱码或不可读的字符。

总之,二进制文件是一种存储任意数据的文件类型,通过以二进制形式存储数据,可以处理各种类型和格式的数据,但需要特定的软件程序来解析和处理。

vs下查看二进制文件: 

5. 文件指针

文件指针简单理解就是一个指向文件的指针。其类型固定为FILE*,这个FILE是一个结构体,这个结构体包含了文件各种的相关信息。

6. 文件的打开和关闭

那么如何打开和关闭一个文件呢?C语言为我们提供了一组打开和关闭文件的函数: 

// 函数原型
// filename: 文件名
// mode: 打开文件的方式
// return val: 返回一个文件指针,这个指针指向这个被打开的文件
FILE *fopen( const char *filename, const char *mode );// 函数原型
// 关闭一个被打开的文件
// stream: 对应的文件指针
// return val: 如果成功关闭,返回0;失败返回EOF
int fclose( FILE *stream );

打开文件的方式:

文件使用方式       大概含义如果指定文件不存在"r" (只读)打开一个已经存在的文本文件出错"w"(只写)打开一个文本文件建立一个新文件
"a"(追加)
向文本文件尾部追加数据建立一个新文件"rb"(只读)打开一个已经存在的二进制文件出错"wb"(只写)打开一个二进制文件建立一个新文件"ab"(追加)向二进制文件追加数据建立一个新文件"r+"(读写)打开一个已经存在的文本文件出错"w+"(读写)打开一个文件建立一个新文件"a+"(追加)向文件尾部追加数据建立一个新文件"rb+"打开一个已经存在的二进制文件出错"wb+"打开一个二进制文件建立一个新文件"ab+"向一个二进制文件尾部追加数据建立一个新文件

现在,我们可以尝试打开一个文件和关闭文件

void Test1(void)
{// 以文本写的方式打开文件FILE* fp = fopen("log.txt", "w");// 打开失败返回NULLif (fp == NULL){perror("open failed");exit(-1);}else{// 关闭文件fclose(fp);}
}

7. 文件的顺序读写

对于下面的函数我个人的理解:将操作者当成"内存",被操作者即"对象"是一个流

功能函数适用于从一个流中读取一个字符

int fgetc( FILE *stream );

所有输入流向一个流中写一个字符

int fputc( int c, FILE *stream );

所有输出流

Get a string from a stream

char *fgets( char *string, int n, FILE *stream );

所有输入流

Write a string to a stream

int fputs( const char *string, FILE *stream );

所有输出流

Read formatted(格式化) data from a stream

int fscanf( FILE *stream, const char *format [, argument ]... );

所有输入流

Print formatted data to a stream

int fprintf( FILE *stream, const char *format [, argument ]...);

所有输出流

Reads data from a stream

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

文件

Writes data to a stream.

size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

文件

下来我们对上面的函数一一演示一下:

7.1. fgetc 

// Read a character from a stream or stdin;
// 读取失败会返回EOF(end of file)
// success: 返回读取的字符
int fgetc( FILE *stream );
void Test2(void)
{// 以文本读打开一个文件FILE* fp = fopen("Test.c", "r");assert(fp);// 如果没有遇到EOF,就继续读while (!feof(fp)){//每次读取一个字符,并向标准输出写入printf("%c", fgetc(fp));}// 关闭一个文件fclose(fp);
}

7.2. fputc

Writes a character to a stream or to stdout.
// ch: 你要写入的字符
// stream: 你要向哪个流写入
// success: return ch
// failed: return EOF
int fputc( int c, FILE *stream );
void Test3(void)
{char ch = 'a';while (ch <= 'z'){// 向标准输出(stdout)写入chfputc(ch, stdout);++ch;}
}

7.3. fgets

//Get a string from a stream.// string: 数据的存储位置
// n: 每次最大读取字符的个数
// stream: 从那个流中读?
// success: 返回读取字符串的起始位置
// failed: 返回NULL
char *fgets( char *string, int n, FILE *stream );
#define BUFFER_MAX 64
void Test4(void)
{char str[BUFFER_MAX] = { 0 };FILE* fp = fopen("Test.c", "r");assert(fp);while (fgets(str, BUFFER_MAX, fp) != NULL){printf("%s", str);}fclose(fp);
}

7.4. fputs

// Write a string to a stream.
// string 你要写入的字符串的起始地址
// stream 你要想哪个流写入
// success: 返回一个!负值
// failed: 返回EOF
int fputs( const char *string, FILE *stream );
void Test5(void)
{const char* str = "hehe\n";for (size_t i = 0; i < 5; ++i){// 向标准输出写入特定字符串fputs(str, stdout);}
}

7.5. fscanf

//Read formatted data from a stream.
// 从特定流(所有输入流)读取格式化数据,与scanf十分类似
// 只不过scanf是固定的从标准输入流读取数据
int fscanf( FILE *stream, const char *format [, argument ]... );
#define BUFFER_MAX 64
void Test6(void)
{FILE* fp = fopen("log.txt1", "r");assert(fp);char str[BUFFER_MAX] = { 0 };while (!feof(fp)){fscanf(fp, "%s", str);printf("%s\n", str);}fclose(fp);
}

7.6. fprintf

// Print formatted data to a stream.
// 向特定流(所有输出流)写入格式化数据
// 与printf十分类似,不过printf是默认向标准输出流写入格式化数据
// success: 返回已写入的字节数
// failed: 返回一个负值
int fprintf( FILE *stream, const char *format [, argument ]...);
void Test7(void)
{const char* str = "haha\n";int* ptr = (int*)malloc(sizeof(int)* 5);for (size_t i = 0; i < 5; ++i){// 其返回值代表每次写入的字节数// 向标准输出流写入特定字符串ptr[i] = fprintf(stdout, "%s", str);}for (int i = 0; i < 5; ++i){printf("%d ", *(ptr + i));}free(ptr);ptr = NULL;
}

7.8. sscanf

// Read formatted data from a string// buffer: 存储数据的起始地址
// sscanf  从一个字符串提取出格式化的数据
// failed: return EOF
int sscanf( const char *buffer, const char *format [, argument ] ... );
typedef struct PeoInfo
{char name[15];int age;
}Info;void Test8(void)
{const char* buffer = "cuihua 18";Info tmp = { 0 };// 从buffer这个字符串提取成格式化的数据sscanf(buffer, "%s%d", tmp.name, &tmp.age);printf("%s %d\n", tmp.name,tmp.age);
}

7.9. sprintf

// Write formatted data to a string.// buffer: 存储将格式化的数据转为stirng的结果
// sprintf 就是将格式化的数据转化为一个字符串int sprintf( char *buffer, const char *format [, argument] ... );
void Test9(void)
{char buffer[BUFFER_MAX] = { 0 };Info tmp = { "cuihua", 18 };// 将格式化数据转化为一个字符串sprintf(buffer, "%s %d\n", tmp.name, tmp.age);printf("%s", buffer);
}

7.9. fread

// Reads data from a stream.
// buffer: 缓冲区
// size: 每次读取的字节数
// count: 要读取多少次
// stream: 从特定流读取size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
void Test10(void)
{char str[BUFFER_MAX] = { 0 };FILE* fp = fopen("Test.c", "r"); assert(fp);// 从fp这个流中读取BUFFER_MAX-1个有效字符fread(str, BUFFER_MAX - 1, 1, fp);printf("%s", str);fclose(fp);
}

7.10. fwrite

//Writes data to a stream.// buffer: 指向被写入的数据
// size: 每次写多少个字节
// count: 写多少次
// stream: 向哪个流写入
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
void Test11(void)
{const char* str = "hehe\n";for (size_t i = 0; i < 5; ++i){// 向标准输出流写入str这个指针指向的内容,每次写size个字节fwrite(str, strlen(str), 1, stdout);}
}

8. 文件的随机读写

8.1. fseek

//Moves the file pointer to a specified location.// fseek 可以根据指针的位置 和 偏移量(offset) 来定位文件指针
// origin 初始位置
// SEEK_CUR 文件指针当前的位置
// SEEK_END 文件末尾的位置
// SEEK_SET 文件开始的位置
int fseek( FILE *stream, long offset, int origin );
void Test12(void)
{const char* str = "abcdefg";FILE* fp = fopen("data.txt", "w");assert(fp);fwrite(str, strlen(str), 1, fp); // 此时data.txt的内容就是 abcdeffclose(fp);FILE* fp1 = fopen("data.txt", "r"); char ch = 0;// 如果我按照顺序读取,那么第一次读必然是ach = fgetc(fp1);printf("%c\n", ch);  // 必定是a// 那如果我此时像读取d呢// 由于此时的文件指针fp指向了b,那么 + 2就到了d// 故 offset = 2fseek(fp1, 2, SEEK_CUR);ch = fgetc(fp1);printf("%c\n", ch);  // d// 那如果我此时像读取最后一个字符呢,也就是g,如何读取呢?// SEEK_END 文件的末尾fseek(fp1, -1, SEEK_END);ch = fgetc(fp1);printf("%c\n", ch); // gfclose(fp1);
}

8.2. ftell

// Gets the current position of a file pointer.
// ftell函数可以返回当前文件指针相对于起始位置的偏移量
long ftell( FILE *stream );
void Test13(void)
{FILE* fp = fopen("data.txt", "r");// 这个文件的数据: abcdefgassert(fp);fseek(fp, -1, SEEK_END); // 此时这个文件指针指向gprintf("%d\n", ftell(fp)); // 此时就是6fclose(fp);
}

8.3. rewind

//Repositions the file pointer to the beginning of a file.
// 让当前文件指针回到文件的起始位置
void rewind( FILE *stream );
void Test14(void)
{FILE* fp = fopen("data.txt", "r");// 这个文件的数据: abcdefgassert(fp);fseek(fp, -1, SEEK_END); // 此时这个文件指针指向gprintf("%d\n", ftell(fp)); // 此时就是6rewind(fp); // 让这个文件指针回到文件的起始位置printf("%d\n", ftell(fp)); // 此时就是0fclose(fp);
}

9. 文件结束的判定

// Tests for end-of-file on a stream.
// 测试文件是如何结束的
// 如果遇到了EOF(即文件指针到了文件末尾),return !0
// otherwise, return 0int feof( FILE *stream );
牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
而是应用于当文件读取结束的时候,feof判断是读取失败结束,还是遇到文件尾结束
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"C文件操作":http://eshow365.cn/6-28366-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!