IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 22 2 24 C语言学习总结(文件操作) -> 正文阅读

[C++知识库]22 2 24 C语言学习总结(文件操作)

一 文件

1 程序文件

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

2 数据文件

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

3 文件名

文件名包含3部分:文件路径+文件名主干+文件后缀

c:\code\test.txt

二 文件打开和关闭

1 文件指针

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE.

struct _iobuf 
{
    char *_ptr;
    int   _cnt;
    char *_base;
    int   _flag;
    int   _file;
    int   _charbuf;
    int   _bufsiz;
    char *_tmpfname;
};
typedef struct _iobuf FILE;
//创建一个FILE*的指针变量来维护这个FILE结构的变量
FILE* pf;//文件指针变量

2 打开和关闭

fopen 与 fclose

FILE *fopen( const char *filename, const char *mode );
Return Value

Each of these functions returns a pointer to the open file. A null pointer value indicates an error. 

"r"

Opens for reading. If the file does not exist or cannot be found, the fopen call fails.

"w"

Opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"

Opens for writing at the end of the file (appending) without removing the EOF marker before writing new data to the file; creates the file first if it doesn’t exist.

"r+"

Opens for both reading and writing. (The file must exist.)

"w+"

Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

?

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
    //打开文件
    FILE* pf = fopen("test.txt","w");//注意是""
    if (pf == nullptr)
    {
        printf("fopen fail\n");
        exit(-1);
    }
    //写文件
    //...

    //关闭文件
    fclose(pf);
    pf = nullptr;
    return 0;
}
//打开文件
FILE* pf = fopen("tesst.txt","r");//注意是""
if (pf == nullptr)
{
    //printf("fopen fail\n");
    printf("%s\n",strerror(errno));//No such file or directory
    exit(-1);
}

解释:

“r”:以只读的形式打开文本文件(不存在则出错)
“w”:以只写的形式打开文本文件(若不存在则新建,反之,则从文件起始位置写,覆盖原内容)
“a”:以追加的形式打开文本文件(若不存在,则新建;反之,在原文件后追加)
“r+”:以读写的形式打开文本文件(读时,从头开始;写时,新数据只覆盖所占的空间)
“wb”:以只写的形式打开二进制文件
“rb”:以只读的形式打开二进制文件
“ab”:以追加的形式打开一个二进制文件
“rb+”:以读写的形式打开二进制文件。
“w+”:首先建立一个新文件,进行写操作,然后从头开始读(若文件存在,原内容将全部消失)
“a+”:功能与”a”相同。只是在文件尾部追加数据后,可以从头开始读
“wb+”:功能与”w+”相同。只是在读写时,可以由位置函数设置读和写的起始位置
“ab+”:功能与”a+”相同。只是在文件尾部追加数据之后,可以由位置函数设置开始读的起始位置

3 相关的库函数

文件的打开
fopen():打开文件

文件的关闭
fclose():关闭文件

文件的读写
fgetc():读取一个字符 适用于所有输入流
fputc():写入一个字符
fgets():读取一个字符串
fputs():写入一个字符串
fprintf():写入格式化数据
fscanf():格式化读取数据
fread():读取数据
fwrite():写入数据

文件状态检查
feof():文件是否结束
ferror():文件读/写是否出错
clearerr():清除文件错误标志
ftell():文件指针的当前位置

文件指针定位
rewind():把文件指针移到开始处
fseek():重定位文件指针

三 文件顺序读写

1 fgetc&fputc

int main(int argc, char const *argv[])
{
    //打开文件
    FILE* pf = fopen("data.txt","w");//注意是""
    if (pf == nullptr)
    {
        printf("%s\n",strerror(errno));//No such file or directory
        exit(-1);
    }
    //写文件
    char ch = 0;
    for (ch  = 'a'; ch < 'z'; ch++)
    {
        fputc(ch,stdout);//写到屏幕上了 abcdefghijklmnopqrstuvwxy
    }

    //关闭文件
    fclose(pf);
    pf = nullptr;
    return 0;
}
for (ch  = 'a'; ch < 'z'; ch++)
{
    fputc(ch,pf);//写到文件里面 abcdefghijklmnopqrstuvwxy
}
//读文件
int ch = 0;//用int既能接受ASCII 也能接受EOF
while ((ch = fgetc(pf)) != EOF)
{
    printf("%c ",ch);
}

2 fputs&fgets

//写一行
fputs("hello world\n",pf);
fputs("hello\n",pf);
//读文件 读一行
char buf[1000] = {0};
fgets(buf, 1000, pf); //实际读999个
printf("%s",buf);

3 文件拷贝

//将data.txt拷贝一份 生成data2.txt
int main(int argc, char const *argv[])
{
    FILE *pr = fopen("data.txt", "r");
    if (pr == NULL)
    {
        printf("open for reading::%s", strerror(errno));
        return 0;
    }
    FILE *pw = fopen("data2.txt", "w");
    if (pw == NULL)
    {
        printf("open for writing::%s", strerror(errno));
        // pw开辟失败
        fclose(pr);
        pr = NULL;
        return 0;
    }
    //拷贝文件
    int ch = 0;
    while ((ch = fgetc(pr)) != EOF)
    {
        fputc(ch, pw); //读一个写一个
    }

    //关闭文件
    fclose(pr);
    pr = NULL;
    fclose(pw);
    pw = NULL;
    system("pause");
    return 0;
}

4 fprintf&fscanf

struct Stu
{
	char name[20];
	int age;
	double d;
};
int main()
{
	struct Stu s = { "张三", 20, 95.5 };
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//写格式化的数据
	fprintf(pf, "%s %d %lf", s.name, s.age, s.d);

	fclose(pf);
	pf = NULL;

	return 0;
}
fprintf(stdout, "%s %d %lf", s.name, s.age, s.d);
//输出到屏幕上也行
int main()
{
	struct Stu s = { 0 };
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//读格式化的数据 从data.txt中读
	fscanf(pf, "%s %d %lf", s.name, &(s.age), &(s.d));

	printf("%s %d %lf\n", s.name, s.age, s.d);

	fclose(pf);
	pf = NULL;

	return 0;
}

5 fwrite&fread

//二进制的写
int main()
{
    struct Stu s[2] = {{"张三", 20, 96}, {"李四", 20, 86}};
    FILE *pf = fopen("data.txt", "wb");
    if (pf == NULL)
    {
        printf("%s\n", strerror(errno));
        return 0;
    }
    //按照二进制的方式写入
    //数组名本身就是地址
    fwrite(s,sizeof(struct Stu),2,pf);//写2组
    //注意二进制的方式写进去后,文本方式打开的是乱码,需要通过二进制编辑器打开
    fclose(pf);
    pf = NULL;
    return 0;
}
//二进制的读
int main()
{
    struct Stu s[2] = {0};
    FILE *pf = fopen("data.txt", "rb");
    if (pf == NULL)
    {
        printf("%s\n", strerror(errno));
        return 0;
    }
    //按照二进制的方式读出来
    fread(s,sizeof(struct Stu),2,pf);//写2组
    printf("%s %d %lf\n",s[0].name,s[0].age,s[0].d);    
    fclose(pf);
    pf = NULL;
    return 0;
}

6 文件版Contact

void LoadContact(Contact *pc)
{
	//从文件加载数据
	FILE *pf = fopen("contact.txt", "rb");
	if (pf == nullptr)
	{
		printf("InitContact:: open for reading :: %s\n", strerror(errno));
	}
	//读取文件
	Peoinfo buf = {0};
	while (fread(&buf, sizeof(Peoinfo), 1, pf))
	{
		//放进去前要检测容量是否足够
		check_capacity(pc);
		pc->data[pc->sz] = buf;
		pc->sz++;
	}
}
void SaveContact(Contact *pc)
{
	//打开文件
	FILE *pf = fopen("contact.txt", "wb");
	if (pf == nullptr)
	{
		printf("SaveContact::%s\n", strerror(errno));
		exit(-1);
	}
	//写文件
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//一次写1组,data指向一块连续空间,每次写入的地址要增加
		fwrite(pc->data + i, sizeof(Peoinfo), 1, pf);
	}

	//关闭文件
	fclose(pf);
	pf = nullptr;
}

7 sscanf&sprintf

scanf 从标准输入流(stdin)上进行格式化输入
printf 想标准输出流(stdout)上进行格式化的输出

fscanf 从标准输入流/指定的文件流上读取格式化的数据
fprintf 把数据按照格式化的方式输出到标准输出流/指定的文件流

sscanf 从一个字符串中提取(转化)出格式化的数据
sprintf 吧一个格式化的数据转换成字符串

int main(int argc, char const *argv[])
{
    struct Stu s = {"Tom", 20, 98};
    struct Stu tmp = {0};
    char buf[100] = {0};
    sprintf(buf,"%s %d %lf",s.name,s.age,s.d);
    printf("%s\n",buf);//Tom 20 98.000000

    sscanf(buf,"%s %d %lf",s.name,&(s.age),&(s.d));
    printf(buf,"%s %d %lf",tmp.name,tmp.age,tmp.d);//Tom 20 98.000000
    return 0;
}

四 文件的随机读写

1 fssek

根据文件指针的位置和偏移量来定位文件指针

int fseek ( FILE * stream, long int offset, int origin );
int main(int argc, char const *argv[])
{
    FILE *pf = fopen("test.txt", "r");//abcdef
    if (pf == nullptr)
    {
        cout << strerror(errno) << endl;
        return 0;
    }

    //读文件
    char ch = fgetc(pf);
    cout << ch << endl;
    ch = fgetc(pf);
    cout << ch << endl;
    //定位文件指针
    //fseek(pf, 3, SEEK_CUR);
    //fseek(pf,5,SEEK_SET);//SET表示从起始位置开始偏移
    fseek(pf, -1, SEEK_END);//END从结束位置开始偏移,偏移-1就指向end
    ch = fgetc(pf);
    cout << ch << endl;//f
    fclose(pf);
    pf = nullptr;
    system("pause");
    return 0;
}
int main(int argc, char const *argv[])
{
    FILE *pf = fopen("test.txt", "w");//abcdef
    if (pf == nullptr)
    {
        cout << strerror(errno) << endl;
        return 0;
    }
    //写文件
    int ch = 0;
    for (ch = 'a'; ch <= 'z'; ch++)
    {
        fputc(ch,pf);
    }
    
    //读文件
    fseek(pf, -1, SEEK_END);//END从结束位置开始偏移,偏移-1就指向end
    fputc('@',pf);//把z改成#
    fclose(pf);
    pf = nullptr;
    system("pause");
    return 0;
}

2 ftell

返回文件指针相对于起始位置的偏移量

long int ftell ( FILE * stream );
int main(int argc, char const *argv[])
{
    FILE *pf = fopen("test.txt", "r");//abcdef
    if (pf == nullptr)
    {
        cout << strerror(errno) << endl;
        return 0;
    }

    //读文件
    char ch = fgetc(pf);
    cout << ch << endl;//a
    ch = fgetc(pf);
    cout << ch << endl;//b
    
    //返回偏移量
    cout << ftell(pf) << endl;//2
    fclose(pf);
    pf = nullptr;
    system("pause");
    return 0;
}

3 rewind

让文件指针的位置回到文件的起始位置

void rewind ( FILE * stream );
int main(int argc, char const *argv[])
{
    FILE *pf = fopen("test.txt", "r");//abcdef
    if (pf == nullptr)
    {
        cout << strerror(errno) << endl;
        return 0;
    }

    //读文件
    char ch = fgetc(pf);
    cout << ch << endl;//a
    ch = fgetc(pf);
    cout << ch << endl;//b
    
    //返回偏移量
    cout << ftell(pf) << endl;//2

    rewind(pf);
    //fseek(pf, 0, SEEK_SET); 也有这样的效果
    cout << ftell(pf) << endl;//0
    fclose(pf);
    pf = nullptr;
    system("pause");
    return 0;
}

五 文件结束判定

1 feof

feof不是用来判断文件结束的,而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇

到文件尾结束

2 文本文件

fgetc判断是否为EOF

fgets判断返回值是否为NULL

int main(void) 
{
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) 
    {
        perror("File opening failed");
        return EXIT_FAILURE;
    }
    //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
    { 
        putchar(c);
    }
    //判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

3 二进制文件

fread判断返回值是否小于实际要读的个数

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
#include <stdio.h>
enum { SIZE = 5 };
int main(void) 
{
    double a[SIZE] = {1.0,2.0,3.0,4.0,5.0};
    FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
    fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组
    fclose(fp);
    double b[SIZE];
    fp = fopen("test.bin","rb");
    size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
    if(ret_code == SIZE) 
    {
        puts("Array read successfully, contents: ");
        for(int n = 0; n < SIZE; ++n) 
            printf("%f ", b[n]);
        putchar('\n');
    } 
    else 
    { 
        // error handling
        if (feof(fp))
            printf("Error reading test.bin: unexpected end of file\n");
        else if (ferror(fp)) 
        {
            perror("Error reading test.bin");
        }
    }
    fclose(fp);

4 ferror

int ferror( FILE *stream );

六 文件缓冲区

ANSIC 标准采用**“缓冲文件系统”处理数据文件,也就是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。**
从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。
如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)

不同编译器缓冲区实现机制不一样

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 11:12:28  更:2022-02-26 11:14:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:38:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码