文件读写操作(C++)

目录

前言

一、文件打开方式

二、写文件

1.文本文件写入

2.二进制写入

三、读文件

1.文本文件读出

2.二进制读出 

四、其他操作

1.文件位置控制

2.错误处理

3.文件流格式化


前言

       当我们谈论C++的文件读写操作时,我们实际上是在讨论如何与计算机的存储系统进行交互,以便读取、写入、修改和保存数据。文件读写是编程中不可或缺的一部分,它使得我们能够持久化地保存数据,以便在程序运行之间或多次运行之间保持数据的一致性。

       在C++中,文件读写操作通常通过标准库中的文件流对象来实现,如ifstream(用于输入文件)和ofstream(用于输出文件)。这些对象提供了丰富的成员函数,使得我们可以以多种方式读取和写入文件,如按字符、按行或按块。

       文件读写操作不仅涉及基本的读取和写入功能,还包括对文件位置的控制(如移动文件指针)、错误处理(如检查文件是否成功打开)以及文件流的格式化(如设置输出宽度、填充字符等)。

       掌握C++的文件读写操作对于开发者来说至关重要,它能够帮助我们有效地管理数据,实现数据的持久化存储,并在需要时从文件中恢复数据。无论是创建日志文件、读取配置文件,还是处理大量数据,文件读写都是一项关键技能。

       在接下来的讨论中,我们将深入探讨C++文件读写的各个方面,包括如何打开和关闭文件、如何读取和写入数据,以及如何处理可能出现的错误和异常情况。通过学习和实践这些技能,你将能够更加熟练地处理文件,并在你的C++程序中实现高效的数据管理。


一、文件打开方式

   在C++的文件操作中,文件的指定打开方式有多种,它们通常包含在头文件#include <fstream>中。主要的打开方式有以下几种:

  1. ios::in:打开一个可读取的文件。如果文件不存在,打开操作将失败。
  2. ios::out:打开一个可写入的文件。如果文件不存在,会创建一个新文件;如果文件已存在,那么文件内容会被清空。
  3. ios::app:以追加模式打开文件。写入的所有数据将被追加到文件末尾,而不是覆盖原有内容。如果文件不存在,会创建一个新文件。
  4. ios::ate:打开文件后立即将文件定位在文件尾。这通常与ios::in或ios::in | ios::out结合使用,用于读取文件的剩余部分或在文件末尾追加内容。
  5. ios::trunc:如果文件已存在,打开文件时会清空已存在的文件内容。这通常与ios::out结合使用。
  6. ios::binary:以二进制模式打开文件,而不是文本模式。这通常用于处理非文本文件,如图像或音频文件。

       这些打开方式可以单独使用,也可以组合使用。例如,ios::in | ios::binary表示以二进制模式打开文件以进行读取操作。但请注意,并非所有的打开方式组合都是有意义的。例如,ios::in和ios::trunc的组合是没有意义的,因为准备读取文件流时,trunc模式会清空文件流。

       在使用这些打开方式时,通常会通过文件流对象的open成员函数来指定。例如:

std::ifstream ofs;  
ofs.open("test.txt", std::ios::in | std::ios::binary);

       这段代码将尝试以二进制模式打开一个名为"example.txt"的文件以进行读取操作。如果文件打开成功,后续就可以通过infile对象来读取文件内容了。

       如果打开失败,可以通过调用is_open(),检查它的返回值来确定是否成功打开了文件。 如果返回 true,则表示文件已成功打开;如果返回 false,则表示打开失败,你应该处理这个错误情况。


二、写文件

1.文本文件写入

#define _CRT_SECURE_NO_WARNINGS 1
using namespace std;
#include<fstream>

#include<iostream>
#include<string.h>

//文本文件 写文件
void test01()
{
	//1、包含头文件fstream
    //2、创建流对象
	ofstream ofs;
	//3、指定打开方式
	ofs.open("test.txt", ios::out);
    //在当前vs文件目录下创建以test命名的文件
	//4、写内容
	ofs << "姓名:张三" << endl;
	ofs << "性别:男" << endl;
	ofs << "年龄:18" << endl;
	//5、关闭文件
	ofs.close();
}

int main()
{
	test01();
	return 0;
}

2.二进制写入

       ios::binary:指定以二进制模式打开文件,而不是默认的文本模式。在文本模式下,某些平台(如Windows)会对换行符进行特殊处理(例如,将 "\n" 转换为 "\r\n")。在二进制模式下,文件会按字节原样读写,不进行任何此类转换。

class Person
{
public:
	char m_Name[64];//姓名
	int m_Age;//年龄
	char m_Sex[6];//性别
};
void test01()
{
	//1、包含头文件
	//2、创建流对象
	ofstream ofs("person.txt", ios::out | ios::binary);//两种模式的结合
	//3、打开文件
	/*ofs.open("person.txt", ios::out | ios::binary)*/
    //4、写文件
	Person p = { "张三",18 ,"男"};
	ofs.write((const char*)&p, sizeof(Person));
	//5、关闭文件
	ofs.close();
}

int main()
{
	test01();

	return 0;
}

三、读文件

1.文本文件读出

       本案例中将给四种文件读出的方法,并附带详细解释,助你轻松理解掌握文件读出。

//文本文件 读文件
void test()
{
	//1、包含头文件
	//2、创建流对象
	ifstream ifs;
	//3、打开文件 并且判断打开是否成功
	ifs.open("test.txt", ios::in);
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	//4、读数据
	//第一种
    //这行代码定义了一个字符数组buf,大小为1024字节,并将所有元素初始化为0。
    //这个数组用作缓冲区,用于存储从文件读取的数据。
	char buf[1024] = { 0 };
    /*这里使用了一个while循环,条件是ifs >> buf。ifs >> buf尝试从输入文件流ifs中读取数据到 
      缓冲区buf。当读取成功时,该表达式返回true,循环继续执行;当读取失败或到达文件末尾时, 
      返回false,循环终止。
      在默认情况下,ifstream对象使用空白字符(如空格、制表符、换行符等)作为分隔符来分隔输入 
      数据。因此,ifs >> buf将读取一个由空白字符分隔的字符串(直到达到缓冲区的大小限制或遇到 
      文件结束)到buf中。*/
	while (ifs >> buf)
	{
        //在循环的每次迭代中,这行代码将缓冲区buf中的内容输出到标准输出,并在其后添加一个换 
        //行符。这样,每次从文件中读取一个字符串时,它都会被打印到控制台上,每个字符串后面跟 
        //着一个换行符。
		cout << buf << endl;
	}

	//第二种
    /*
    这里定义了一个字符数组buf,用于存储从文件中读取的每一行数据。数组的大小为1024字节,并且 
    所有元素都被初始化为0。初始化所有元素为0确保了如果读取的行数据不足1024字节,那么剩余的缓 
    冲区部分将包含空字符(即字符串的结束符)。
    */
	char buf[1024] = { 0 };
    /*
    getline函数尝试从ifs输入流中读取一行数据,并将其存储在buf缓冲区中。它接受两个参数:一个 
    字符数组(用于存储读取到的数据)和一个整数(指定缓冲区的大小)。这里,sizeof(buf)返回缓 
    冲区buf的大小(以字节为单位),确保不会超出缓冲区的边界。

    当getline成功读取一行时,它返回true,循环继续执行。如果到达文件末尾或发生其他读取错误, 
    getline返回false,循环终止。

    与ifs >> buf不同,getline读取整行数据,包括行尾的换行符(如果有的话)。换行符也会被存储 
    在buf中,直到缓冲区满或读取到文件末尾。如果缓冲区在行结束之前就已经满了,getline将只读取 
    到缓冲区大小允许的部分,并设置流的状态以指示发生了截断。
    */
	while (ifs.getline(buf, sizeof(buf)))
	{
    /*
    在循环的每次迭代中,这行代码将缓冲区buf中的内容(即文件中的一行)输出到标准输出,并在其后 
    添加一个换行符。这样,文件中的每一行都会被打印到控制台上,每行后面跟着一个换行符。

    需要注意的是,由于getline将换行符也存储在buf中,所以输出的每一行末尾也会包含原始文件中的 
    换行符(如果文件中有的话)。如果你不希望输出中包含换行符,你可以通过其他方式(如使用字符 
    串操作函数)来移除它。
    */
		cout << buf << endl;
	}

	//第三种
    /*
    这里定义了一个std::string类型的变量buf,用于存储从文件中读取的每一行数据。使用 
    std::string而不是字符数组(char[])的好处是,std::string会自动管理内存,并且在需要时可 
    以动态地增长或缩小其大小。
    */
	string buf;
    /*
    getline是一个从<string>库中提供的函数,它用于从输入流中读取一行数据,并将其存储在一个 
    std::string对象中。这里,getline从ifs输入流(可能是一个ifstream对象)中读取一行,并将 
    其存储在buf字符串中。

    当getline成功读取一行时,它返回true,循环继续执行。如果到达文件末尾或发生其他读取错误, 
    getline返回false,循环终止。
    */
	while (getline(ifs,buf))
	{
    /*
    使用std::string代替字符数组使得代码更加简洁和易读,同时也减少了出错的可能性,因为不需要 
    手动管理字符数组的内存和大小。
    */
		cout << buf << endl;
	}

	//4、第四种
	char c;
    /*
    get函数从ifs输入流中读取下一个字符,并将其赋值给c。如果读取成功,get返回读取到的字符;如 
    果到达文件末尾或发生读取错误,get返回EOF(End Of File,文件结束标志)。

    这个while循环会持续执行,直到get返回EOF为止。在每次循环迭代中,它都会检查(c = 
    ifs.get())的结果是否不等于EOF。如果不等于EOF,则执行循环体;否则,退出循环。
    */
	while ((c = ifs.get())!=EOF)//EOF  end of file
	{
		cout << c;//会自动读取回车符
	}
	cout << endl;//这行代码会在所有字符都被输出到控制台后执行,
                 //添加一个换行符,使得输出更加整洁。
    //总结起来,这段代码以字符为单位读取文件内容,并将每个字符原样输出到控制台上,包括空格、 
    //制表符和换行符等。在输出完整个文件后,它还会添加一个换行符。
	//5、关闭文件
	ifs.close();
}

int main()
{
	test();
	return 0;
}

2.二进制读出 

class Person
{
public:
	char m_Name[64];
	int m_Age;
	char m_Sex[6];
};

void test01()
{
	//1、包含头文件

	//2、创建流对象
	ifstream ifs;

	//3、打开文件,检查对象是否打卡成功
	ifs.open("person.txt", ios::in | ios::binary);

	if (!ifs.is_open())
	{
		cout << "w文件打开失败" << endl;
		return;
	}

	//4、读文件
	Person p;

	ifs.read((char*)&p, sizeof(Person));
	
	cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << " 性别: " << p.m_Sex << endl;

		//5、关闭文件
		ifs.close();
}

int main()
{
	test01();
	return 0;
}

四、其他操作

1.文件位置控制

       文件位置控制通常涉及到移动文件指针,以便在文件的特定位置进行读写操作。这可以通过seekg(用于输入文件流)和seekp(用于输出文件流)成员函数来实现。

#include <iostream>  
#include <fstream>  
#include <string>  
  
int main() {  
    std::ofstream outfile("position_control.txt");  
    if (!outfile.is_open()) {  
        std::cerr << "无法打开文件" << std::endl;  
        return 1;  
    }  
  
    outfile << "Hello" << std::endl;  
    outfile << "World" << std::endl;  
  
    // 将文件指针移动到文件开头  
    outfile.seekp(0, std::ios::beg);  
    outfile << "C++";  
  
    outfile.close();  
  
    std::ifstream infile("position_control.txt");  
    if (!infile.is_open()) {  
        std::cerr << "无法打开文件" << std::endl;  
        return 1;  
    }  
  
    // 读取整个文件内容  
    std::string content((std::istreambuf_iterator<char>(infile)),  
                         std::istreambuf_iterator<char>());  
    std::cout << content << std::endl; // 输出可能是 "C++orld"  
  
    infile.close();  
    return 0;  
}

2.错误处理

       错误处理在文件操作中非常重要。你可以使用fail()bad(), 和 eof() 成员函数来检查流的状态,或者使用is_open()来检查文件是否成功打开

#include <iostream>  
#include <fstream>  
#include <string>  
  
int main() {  
    std::ofstream outfile("nonexistent_directory/file.txt");  
    if (!outfile.is_open()) {  
        std::cerr << "无法打开文件" << std::endl;  
        return 1;  
    }  
  
    // 尝试写入数据  
    outfile << "This is a test." << std::endl;  
  
    // 检查写入是否成功  
    if (outfile.fail()) {  
        std::cerr << "写入文件时发生错误" << std::endl;  
        outfile.clear(); // 清除错误标志  
    }  
  
    outfile.close();  
  
    return 0;  
}

3.文件流格式化

       文件流格式化涉及到设置输出宽度、填充字符、精度等。这可以通过使用std::setwstd::setfillstd::setprecision等操纵器来实现

#include <iostream>  
#include <fstream>  
#include <iomanip> // 包含操纵器  
  
int main() {  
    std::ofstream outfile("formatted_output.txt");  
    if (!outfile.is_open()) {  
        std::cerr << "无法打开文件" << std::endl;  
        return 1;  
    }  
  
    // 设置输出宽度为10,不足部分用0填充  
    outfile << std::setw(10) << std::setfill('0') << 123 << std::endl;  
  
    // 设置浮点数的精度为3位小数  
    double pi = 3.14159265358979323846;  
    outfile << std::fixed << std::setprecision(3) << pi << std::endl;  
  
    outfile.close();  
  
    return 0;  
}

在上面的代码中,

std::setw用于设置输出宽度,

std::setfill用于设置填充字符,

std::fixed用于设置浮点数输出为定点表示法,

std::setprecision用于设置浮点数输出的小数位数。

这些操纵器与文件流对象结合使用,可以方便地控制输出格式。

       请注意,文件流格式化通常更多地用于控制输出到控制台的格式,但同样适用于文件输出流。当输出到文件时,格式化指令会被存储在文件中,并按字面意思输出。如果您希望在打开文件时以特定格式读取数据,那么您需要在写入文件时遵循相同的格式规则,并在读取时相应地解析数据。

 文件操作的有关知识暂时分享到这里,如果需要了解C++更多的知识请关注我后续的文章。

 看到这里,不妨点个攒,关注一下吧!

最后,谢谢你的观看!

  • 57
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QSettings是一个在Qt应用程序中用于读取写入配置信息的强大类。它可以通过读写ini配置文件来实现对应用程序的配置操作。具体的读写操作包括以下几个步骤: 1. 初始化QSettings对象:在使用QSettings之前,需要创建一个QSettings对象,并传入配置文件的路径和格式。例如,可以使用QSettings的构造函数指定ini文件作为配置文件。 2. 读取配置信息:使用QSettings的value()函数可以读取指定配置项的值。该函数接受两个参数,第一个参数是配置项的键值,第二个参数是配置项的默认值。如果配置项存在,则返回其值;如果配置项不存在,则返回默认值。 3. 写入配置信息:使用QSettings的setValue()函数可以写入配置项的值。该函数接受两个参数,第一个参数是配置项的键值,第二个参数是配置项的值。写入的配置项会自动保存到配置文件中。 4. 删除配置信息:使用QSettings的remove()函数可以删除指定的配置项。该函数接受一个参数,即要删除的配置项的键值。删除后的配置项会从配置文件中移除。 综上所述,QSettings提供了方便的方法来读取写入ini配置文件中的配置信息,通过合理使用QSettings,可以轻松管理和存储应用程序的配置信息,提高应用程序的灵活性和可维护性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Qt实战案例之利用QSettings读写ini配置文件.zip](https://download.csdn.net/download/didi_ya/85451941)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Qt 中的 QSettings:配置文件的读写和应用场景](https://blog.csdn.net/qq_46017342/article/details/131585987)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值