来源:黑马程序员
第157讲 C语言操作文件概述
读取文件:输入流
写文件:输出流
读写的方向判断取决与参照,一般我们站在程序的角度判断读写方向。
第158讲 路径
基本概念
路径就是指文件在电脑中的位置,eg:C:\Users\Administrator\Desktop
表示方式
①绝对路径
例如:C:\Users\Administrator\Desktop
绝对路径以盘符作为起始标志,除非认为改动位置是固定所以叫绝对路径。
②相对路径
例如:aaa\a.txt
相对于当前项目而言的位置。
第159讲 转义字符
C语言中路径以字符串形式存在。
\在C语言中代表一个转义字符(改变后面这个符号原本的含义);"代表字符串的开头或者结尾。
所以在代码中如果想要打印\和",需要先在前面加上转义字符。
正确打印当前文件位置的代码:
cpp
#include <stdio.h>
int main()
{
char* path = "E:\\0_C&C++ Projects\\C\\FilePath\\files\\file demo.txt";
printf("%s\n", path);
return 0;
}
注意点
文件路径的末尾必定是一个带有文件格式标识的文件名称(例如:a.txt)!
第160讲 利用fgetc一次读一个字节
文件操作流程
①打开文件 fopen
②读数据 fgetc (file get char,一次读一个字节) fgets(file get string,一次读一行)
fread(跨行处理)
③关闭文件 fclose
函数介绍
fopen
函数原型:
cpp
FILE *fopen(const char *path, const char *mode);
形参介绍:
path
参数指定了要打开文件的路径和名称。
mode
参数指定了文件的打开模式(如只读、只写、追加等)。
mode
参数的一些常用值包括:
一般视频、音频、图片的文件格式是二进制类型,本节课操作文本文件。
作用拓展:
使用 fopen
打开文件后,可以通过一系列的输入/输出函数(如 fread
、fwrite
、fprintf、``fscanf
、fgets
、fputs
等)对文件进行读写操作。完成文件操作后,应使用 fclose
函数关闭文件,以释放与 FILE
对象相关联的资源。
冷知识
部分C++编译器中里面char *path="hello"会报错"const char*类型不能用来初始化char*类型",解决方法也是队中多样的。
fgetc
函数原型:
cpp
int __cdecl fgetc(_Inout_ FILE* _Stream);
形参介绍:Stream 是指向 FILE
对象的指针,该对象标识了要从中读取字符的文件流。
返回值:读取成功则返回读取到的字符,读不到就返回-1。
fclose
函数原型:
cpp
int fclose(FILE* _Stream);
形参介绍:Stream
:指向 FILE
对象的指针,该对象标识了要关闭的文件流。这个 FILE
指针是通过之前对 fopen
、freopen
或 fdopen
的调用获得的。
返回值:如果文件成功关闭,fclose
函数返回 0
。
如果关闭文件时发生错误,返回 EOF
。EOF
是一个在 <stdio.h>
中定义的宏,通常用于表示文件结束或错误条件。
操作实例
①在工程文件内新建一个文本文件,随意写入一行字符。
②修改编码格式为ANSI,步骤如下:
(1)点击文件->另存为;
(2)点击编码,选择为ASNI(少了这一步会输出中文乱码)。
③开始编程。
cpp
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* path = "E:\\0_C&C++ Projects\\C\\Fgetc\\files\\file demo.txt";
FILE* file = fopen(path, "r");
/*调试
if (file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
int c = fgetc(file);
if (c != EOF) {
printf("%c\n", c);
}
else {
printf("No characters read or file is empty.\n");
}
fclose(file);
return EXIT_SUCCESS;
*/
/*待改进
int c = fgetc(file);
printf("%c", c);
c = fgetc(file);
printf("%c", c);
c = fgetc(file);
printf("%c", c);
c = fgetc(file);
printf("%d", c);
fclose(file);
*/
int c;
while ((c=fgetc(file))!=-1)
{
printf("%c", c);
}
fclose(file);
return 0;
}
输出结果:
第161讲 利用fgets一次读一行数据
fgets函数介绍
函数原型:
cpp
char *fgets(char *str, int n, FILE *stream);
形参介绍:
str
:指向用于存储读取到的字符串的字符数组。
n
:指定要读取的最大字符数(包括最后的空字符\0
)。如果读取的字符数(不包括最后的空字符)达到了n-1
,函数将停止读取,并在字符串末尾添加一个空字符\0
。
stream
:指向 FILE
对象的指针,该对象标识了要从中读取数据的输入流。
返回值:
如果成功读取到字符串,fgets
函数返回 str
的地址。
如果读取失败(例如,遇到文件结束符或发生错误),则返回 NULL
。
如果在读取任何字符之前已经到达文件末尾,则 str
的内容保持不变,并返回一个空指针。
使用示例
cpp
#include <stdio.h>
int main()
{
char* path = "E:\\0_C&C++ Projects\\C\\Fgets\\poetry\\静夜思.txt";
FILE* file = fopen(path, "r");
char buffer[1024] = "";
char* str;
while ((str= fgets(buffer, 1024, file))!=NULL) {
printf("%s\n", str);
}
fclose(file);
return 0;
}
输出结果:
注意事项
①fgets每次读取一行数据,以换行符(按下回车键或者叫"\n")为准。
②如果读不到了就会返回NULL。
第162讲 利用fread一次读多个字节
fread函数介绍
函数原型:
cpp
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
形参介绍:
void *ptr
:指向用于存储读取数据的缓冲区的指针。
size_t size
:每个数据项的大小(以字节为单位)。
size_t nmemb
:要读取的数据项的最大数量。
FILE *stream
:指向 FILE
对象的指针,该对象标识了要从中读取数据的输入流。
返回值:
成功时,fread
返回实际读取的元素数量 ,这可能会小于请求的数量 nmemb
,尤其是在遇到文件结束(EOF)或发生错误时。
如果发生错误或到达文件末尾前没有读取任何数据,则返回 0。
代码示例
cpp
#include <stdio.h>
int main()
{
char* path = "E:\\0_C&C++ Projects\\C\\Fread\\poetry\\静夜思.txt";
FILE* file = fopen(path,"r");
char buff[1024];
int num = fread(buff, 1, 1024, file);
//获取文件中的元素数量,24个汉字字符(包括标点)*2byte+3个换行符*1byte=51byte
printf("%d\n", num);
printf("%s",buff);
fclose(file);
return 0;
}
输出结果
注意细节
①Windows64位系统中英文字母占用1个字节,中文字符占用2个字节。
②fread在读取时每次尽可能会把数组装满,返回当前读取到的有效字节数
假设文件为100个字节,数组长度为30;那么接下来读取的流程为:
第一次,读取前面30个字节,把数组给装满,函数返回30;
第二次,读取后面30个字节,把数组给装满,函数返回30;
第三次,读取后面30个字节,把数组给装满,函数返回30;
第四次,读取剩余的10个字节,会把数据放在数组当中,函数返回10;
第五次:没有数据可以被读取了,函数返回0。
所以可以利用这个特性改进代码:
cpp
char* path = "E:\\0_C&C++ Projects\\C\\Fread\\poetry\\静夜思.txt";
FILE* file = fopen(path,"r");
char buff[100];
int num ;
while ((num = fread(buff, 1, 100, file)) != 0)
{
for (int i = 0; i <num ; i++) {
printf("%c",buff[i]); //注意%c后不能有其他东西
}
}
fclose(file);
return 0;
while循环内判断是否到达到达文件末尾,for循环遍历字符数组打印。
输出结果:
第163讲 三种写出数据的方式
基本概念
写出数据就是把程序中的数据,写到本地文件中永久存储。
书写步骤
1 打开文件 fopen
2 写数据 fputc fputs fwrite
3 关闭通道 fclose
文件读写模式
fputc
函数原型:
cpp
int fputc(int _Character, FILE* _Stream);
形参介绍:_Character是想要写入的字符的ASCII值,_Stream是指向目标文件的指针。
返回值:如果写入成功,函数返回写入的字符的ASCII码值;如果写入失败(例如,由于磁盘空间不足或文件是只读的),则返回EOF
(在stdio.h
中定义的宏,通常表示-1)。
fputs
函数原型:
cpp
int fputs(char const* _Buffer,FILE* _Stream);
形参介绍:_Buffer是指向要写入文件的字符串的指针;_Stream是
指向 FILE
对象的指针,该对象标识了要写入的文件流。
返回值:写出成功返回非负数,建议忽略
fwrite
函数原型:
cpp
fwrite( void const* _Buffer, size_t _ElementSize, size_t _ElementCount,FILE* _Stream);
形参介绍:
_Buffer
:这是一个指向数据的指针,这些数据将被写入到文件中。注意,由于这是一个 void
类型的指针,所以它可以指向任何类型的数据。但是,你需要确保传递给 _ElementSize
的值正确反映了每个数据元素的大小。
_ElementSize
:这是每个数据元素的大小(以字节为单位)。它告诉 fwrite
每个数据项占用的字节数。
_ElementCount
:这是要写入文件的数据元素的数量。fwrite
会尝试写入指定数量的数据元素到文件中。
_Stream
:这是一个指向 FILE
对象的指针,该对象标识了要写入数据的文件流。
返回值:fwrite
函数返回成功写入的数据元素的数量。注意,这个数量可能小于我们请求的 _ElementCount
,特别是当文件系统的空间不足或发生其他错误时。如果发生错误,我们可以检查 ferror
函数的返回值来确定是否发生了错误。
代码示例
cpp
#include <stdio.h>
int main()
{
char* path = "E:\\0_C&C++ Projects\\C\\FileWrite\\Myfiles\\myfile.txt";
FILE* file=fopen(path, "w");
//ASCII值a->97
int c=fputc(97,file);
printf("%c\n", c);
char* str = "\n银瓶乍破水浆迸";
int n=fputs(str,file);
printf("%d\n", n);
char message[20] = "\n铁骑突出刀枪鸣";
int num=fwrite(message,1,17,file);
printf("%d\n", num);
fclose(file);
return 0;
}
输出结果:
文件里面的现状:
第164讲 多种读写模式
fopen的小细节
fopen(path,"w");如果要写出的文件不存在,编译器可以创建文件,但必须保证前面的文件夹是存在着的。如果文件已经存在,会把原文件清空。
fopen(path,"a");a=append追加写出
fopen的一些其他模式
第165讲 拷贝文件
纯文本文件在打开数据源时可以使用r、w、a模式,通俗地讲windows系统中的记事本可以打开地文件就叫做纯文本文件,例如存储文字地txt、md文件、歌词文件lrc文件等。
代码示例
cpp
#include <stdio.h>
int main()
{
//打开数据源
char* path = "D:\\readme.txt";
FILE* fScource = fopen(path,"r");
//复制文件路径
char* newpath = "E:\\0_C&C++ Projects\\C\\FileCopy\\Container\\copy.txt";
FILE* fCopy = fopen(newpath, "w");
//利用循环读取数据
char arr[1024];
int n;
while ((n=fread(arr,1,1024, fScource))!=0)
{
fwrite(arr,1,n, fCopy);
}
fclose(fScource);
fclose(fCopy);
return 0;
}