C++文件操作(1)

C++文件操作

  • 1.文本的写入及读取
    • 文本文件写入
    • 文本文件读取
  • 2.二进制文件的写入及读取
    • 二进制文件写入
    • 二进制文件读取
  • 3.小结

C++也有处理文件的能力,其功能实现依赖文件流。文件流是C++中用来处理文件输入输出的一种流类。文件流可以用于从文件中读取数据或将数据写入到文件中。C++中的文件流类包括ifstream(用于从文件中读取数据)、ofstream(用于向文件中写入数据)和fstream(用于同时读取和写入文件)。这些文件流类提供了一组成员函数,可以用来打开、关闭、读取和写入文件。使用文件流可以方便地进行文件操作,如读取文件内容、写入数据到文件中等。这里我们主要学习文件的处理方法,想要深度了解文件流的小伙伴可以在学完本节之后再补充相关知识。

1.文本的写入及读取

字符串文件是C++经常处理的一种文件类型,其依赖为i/ostream和fstream类。

文本文件写入

我们看一个向文件中写入内容的例子:

#include<stdio.h>

#include<iostream>
#include<fstream>

#include <string>
using std::string;
using namespace std;
int main()
{
    string filename="test.txt"; // 文件名
    ofstream mytest; // 使用ofstream创建文件输出流对象,名字自拟
    mytest.open(filename); // 打开文件
    // 向文件中写入数据
    mytest<<"这是一个测试\n"<<"我们尝试连续输入内容\n";
    mytest<<"继续测试";
    // 关闭文件
    mytest.close();
}

在这段代码中,filename定义了一个文件名,我们尝试使用文件流打开文件,当当前路径下存在文件时,这段代码会截断文件,即打开文件后删除文件内容,重新进行写入操作,当文件不存在时,会在当前路径下创建文件并写入内容。运行这段代码会在.cpp文件路径下产生一个.txt文件:
在这里插入图片描述
虽然操作成功了,但是这样的做法存在不足和风险,比如我们在打开或创建文件时应当给出文件的确切位置,不应该只让它生成在.cpp文件的路径下;在使用文件之前应当判断文件是否成功打开。
为了解决以上不足,我们先详细了解一下ofstream输出流。ofstream创建了文件输出流对象,而open函数可以带有两个参数,即文件及路径和打开方式。文件的绝对路径有以下写法:

R"(C:\data…\test.txt)" (C++11标准)
“C:\data\…\text.txt”
“C:/data/…/text.txt”

其次,文件的打开方式可以这样规定:

ios::out 截断文件内容打开文件,为参数默认值
ios::truck 截断文件内容,类似于ios::out
ios::app 在文件后添加内容

我们再来测试一下:

int main()
{
    ofstream mytest;
    mytest.open("E:\\c++\\class3start11\\test.txt",ios::app);
    // 使用ios::app 在文件后添加内容
    // 向文件中写入数据
    mytest<<"这是一个测试\n"<<"我们尝试连续输入内容\n";
    // 关闭文件
    mytest.close();
}

再打开文件其内容就变成了:
在这里插入图片描述
此外,文件也不是一定能打开文件的情况,通常情况下无法正常打开文件的情况有:

1.目录不存在
2.磁盘空间已满
3.没有权限(linux系统下常见)

应对这种情况,我们可以使用mytest.is_open()来判断文件是否成功打开:

int main()
{
    ofstream mytest("test.txt",ios::app); // 在创建文件输出流对象时直接提供路径和打开方式参数,
                                          // 不需要再使用open进行打开
    if(mytest.is_open()) // 判断文件是否成功打开
    {
        mytest<<"这是一个测试\n"<<"我们尝试连续输入内容\n";
        // 关闭文件
        mytest.close();
        return 0;
    }
    else
    {
        cout<<"打开文件失败"<<endl;
        return 0;
    }
}

作为演示内容,我们就不写完整路径了。

文本文件读取

读取文本文件内容需要用ifstream输出流进行操作,其参数也是两个,文件名和打开方式。打开方式只能使用使用in:

int main()
{
    // 读取文件参数只有iOS::in
    ifstream mytest("test.txt",ios::in); // 用输入流打开文件,读取文件内容
    if(mytest.is_open())
    {
        cout<<"打开文件成功"<<endl;
        return 0;
    }
}

而后就要读取文件内容了。读取文件内容使用函数getline。getline函数有两个参数,即输出流对象和用于存储读取信息的变量。getline会按行读取文件内容,并返回是否读取成功。它很多重载,但常用的主要有两种方式:

if(mytest.is_open())
{
    string out; // 定义字符串类型out用于接收文件内容
    while(getline(mytest,out)) // 将当前行内容存入out,当前行没有内容时返回值为false
    {
        cout<<out<<endl;  
    }
    // 关闭文件
    mytest.close();
}
else
{
	cout<<"打开文件失败!"<<endl;
}

这样就可以在终端看到执行效果:
在这里插入图片描述
当然,这种用法还有一种比较简单的变种:

int main()
{
    // 读取文件参数只有iOS::in
    ifstream mytest("test.txt",ios::in);
    // 打开文件失败的原因:1.文件不存在2.目录不存在3.没有权限
    if(mytest.is_open())
    {
        string out;
	    while(mytest>>out)
	    {
	        cout<<out<<endl;  
	    }
	    // 关闭文件
	    mytest.close();
    }
    else
    {
		cout<<"打开文件失败"<<endl;
        return 0;
	}
}

这种方式使用起来更简单,我们记住就好。
另外,使用C风格字符串也可以接收文件内容,需要用到另一个getline函数的重载:

int main()
{
    ifstream mytest; 
    mytest.open("test.txt",ios::in)
    if(mytest.is_open())
    {
        char out[21]; // 三个字符存储一个汉字
        // 读取文件一般要用getline函数一行一行读
        while(mytest.getline(out,20)) // getline的一个重载,第一个参数为记录文件内容的字符串名,第二个参数是这个字符串最大下标
        // 如果字符数组不能够存下某行数据,会在对应处直接终止运行退出程序。
        {
            cout<<out<<endl;
        }
    }
    else
    {
        cout<<"打开文件失败"<<endl;
        return 0;
    }
    // 关闭文件
    mytest.close();
}

这个例子中,我们使用的C类型字符串最多可以存储的汉字只有7个,当遇到一行超过7个汉字的情况,会立刻终止运行,但不会报错。如果我们扩大数组的大小(由于换行符的存在,这里至少需要设置成31)就可以完整读取了。但实际中如果遇到这种情况并不好处理,在不知道文本内容的时候,设置足够大的字符数组较难做到,况且如果字符数组设置过大,又会浪费空间,因此这种用法并不推荐。

2.二进制文件的写入及读取

文本文件的读写方便实用,其特点为每个字符都有实际意义,但只能用于处理字符串类型。在实际使用中,很多时候我们需要存取更复杂的类型,比如结构体、整形、图片等,这些内容用字符串处理并不方便。计算机的世界里,只有0和1两个数字,任何数据本质上都是由二进制数描述的,因此如果我们使用二进制对文件进行存取,理论上就可以处理所有文件和数据。C++也为我们提供了这样的存取方法。

二进制文件写入

使用二进制处理文件首先也是要用ofstream创建输出流对象,打开文件时也要额外说明使用二进制方式打开。写入的过程需要使用write函数,具体使用方法示例如下:

// 定义一个需要记录数据的基本结构,也可以使用自定义类或C++基本数据类型
struct Student
{
    char name[32];
    int age;
    char sex;
};
int main()
{
    ofstream mytest("test.doc",ios::binary);
    // 需要再打开方式后面加上binary用于告诉计算机使用二进制方式打开
    // 这里的ios::out可以省略
    if(mytest.is_open())
    {
        Student child={"ZhangSan",15,'m'}; // 
        // 写入文件需要使用write函数
        mytest.write((const char*)&child,sizeof(Student));
        child=Student{"LiSi",20,'m'}; // 重载child,因为child变量之前已经赋值,因此不能直接初始化
        mytest.write((const char*)&child,sizeof(Student)); // 参数为需写入内容的地址(C++要求使用const char*),需写入内容的大小
        
    }
    else
    {
        cout<<"打开文件失败"<<endl;
        return 0;
    }
    // 关闭文件
    mytest.close();
}

这样我们就可以得到一个doc文件了:
在这里插入图片描述
但是它的内容是乱码的,这是因为二进制存储文件是按字节有效的,如果我们不知道存储的方式,是不能够正确解码的。

二进制文件读取

当我们知道数据的具体存储方式时,就可以编写程序查看存储的实际内容了。上例中,我们知道test.doc文件存储的数据是Student结构体,也就可以对它进行解码并查看内容了:

int main()
{
    ifstream mytest("test.doc",ios::in|ios::binary); // 读取二进制文件
    if(mytest.is_open())
    {
        // 二进制文件打开后需要用正确的接收格式接收
        Student child;
        // 二进制文件以数据类型的方式组织数据,没有换行的说法
        // mytest.read((char*)&ZhangSan,sizeof(Student)) 一次只能读取一个结构体数据
        while(mytest.read((char*)&child,sizeof(Student)))
        {
            cout<<child.name<<" "<<child.age<<" "<<child.sex<<endl;
        }
    }
    else
    {
        cout<<"打开文件失败"<<endl;
        return 0;
    }
    
    // 关闭文件
    mytest.close();
}
// 输出为:ZhangSan 15 m
//        LiSi 20 m

这里需要注意几点问题:
1.由于C++中string类型内存布局具有不确定性,因此可能会影响二进制文件的读取,建议使用字符数组存储字符串;
2.一个结构体变量只能初始化一次,想要修改变量内容可以使用赋值或重载的方式;
3.C++处理文本文件时以换行符作为读取内容分隔符,getline函数也是在读取到第一个换行符时返回。二进制文件中换行符只被视为二进制数据,文件读取时以数据块作为分隔。

3.小结

这节主要介绍了C++处理文本文件和二进制文件的部分方法,由于篇幅原因,我们只提到了较为常见的函数和用法。后面的学习中我会继续对文件操作进行补充。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/360328.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开发工具git分支冲突解决

在团队协作的软件开发过程中&#xff0c;Git是一款广泛使用的版本控制系统。然而&#xff0c;当多个开发者同时修改同一文件或代码段时&#xff0c;就会产生分支冲突。解决这些冲突需要仔细的协调和技术知识。本篇博客将介绍Git分支冲突的解决方法&#xff0c;以及开发工具和最…

四工序开料机可以加工什么产品

四工序开料机是木工机械设备中一款重要设备&#xff0c;该设备主要的功能是开料、打孔、拉槽等&#xff0c;一机多用&#xff0c;凭借多功能的加工效果&#xff0c;实现高速加工的效果&#xff0c;那么这样的设备可以加工什么类型的产品呢&#xff1f;大家对此了解多少呢&#…

idea报错 :(java: 找不到符号)

java: 找不到符号 符号: 变量 adminService 位置: 类 com.example.controller.WebController 查到网上一个办法&#xff1a;因为项目是maven&#xff1a;先点clean在点package

anaconda离线安装包的方法

当设备没有网络时&#xff0c;可以使用有网络的设备先下载所需安装包&#xff0c;然后离线拷贝到需要安装的设备&#xff0c;最后安装。 一. 下载所需安装包 下载命令&#xff1a;使用pip download。详细描述参见pip download -h 以"blind-watermark"为例。 pip …

一站式在线协作办公软件ONLYOFFICE,协作更便捷

1、ONLYOFFICE是什么&#xff1f; ONLYOFFICE是一款功能强大的在线协作办公软件&#xff0c;可以创建编辑Word文档、Excel电子表格&#xff0c;PowerPoint&#xff08;PPT&#xff09;演示文稿、Forms表单等多种文件。ONLYOFFICE支持多个平台&#xff0c;无论使用的是 Windows、…

真机调试,微信小程序,uniapp项目在微信开发者工具中真机调试,手机和电脑要连同一个wifi,先清空缓存,页面从登录页进入,再点真机调试,这样就不会报错了

微信小程序如何本地进行真机调试&#xff1f;_unity生成的微信小程序怎么在电脑上真机测试-CSDN博客 微信小程序 真机调试 注意事项 uniapp项目在微信开发者工具中真机调试&#xff0c;手机和电脑要连同一个wifi&#xff0c;先清空缓存&#xff0c;页面从登录页进入&#xf…

怎么保护U盘数据?如何提高U盘的安全性?

U盘作为常用的移动储存设备&#xff0c;能够帮我们存储大量数据。而为了避免数据泄露&#xff0c;我们需要采用专业的方式提高U盘的安全性。那么&#xff0c;怎么保护U盘数据呢&#xff1f;下面我们就一起来了解一下。 如何提高U盘的安全性&#xff1f; 提高U盘数据安全性的方…

3DMAX一键生成样条线纤维插件使用方法

3DMAX一键生成样条线纤维插件使用教程 3DMAX一键生成样条线纤维插件&#xff0c;是一个强大的脚本工具&#xff0c;用于围绕选定的样条线路径创建纤维。它有许多设置用于微调纤维的形状和材质。 【适用版本】 3dMax2010 – 2024&#xff08;不仅限于此范围&#xff09; 【安装…

Rust基础篇之注释、函数

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期专栏回顾 专栏描述…

Wireshark网络协议分析 - UDP协议

在我的博客阅读本文 文章目录 1. 基础2. 实战2.1. 用Go写一个简单的UDP服务器与客户端2.2. Wireshark抓包分析 3. UDP与TCP的区别4. 参考资料 1. 基础 UDP包的数据结构&#xff1a; 2. 实战 2.1. 用Go写一个简单的UDP服务器与客户端 我们这里使用Golang写了一个简单的9830端…

appsmith安装手记:4.Sql server数据库容器安装

appsmith安装好&#xff0c;那就可以看是练练手。 数据当然是来自数据库&#xff0c;那就连接局域网中现成的一台数据库服务器试试&#xff0c;但是连接数据库的时候一直错误。 找到/home/appsmith/backend 目录下的日志&#xff0c;看到了错误&#xff1a; [rootlocalhost bac…

【HarmonyOS应用开发】ArkUI 开发框架-基础篇-第二部分(八)

八、Column&Row组件的使用 概述 一个丰富的页面需要很多组件组成&#xff0c;那么&#xff0c;我们如何才能让这些组件有条不紊地在页面上布局呢&#xff1f;这就需要借助容器组件来实现。 容器组件是一种比较特殊的组件&#xff0c;它可以包含其他的组件&#xff0c;而…

Qt 调用系统键盘

Wow64DisableWow64FsRedirection(&pvoid) 函数用于禁用 32 位 Windows 程序对文件系统重定向的支持。它将禁用文件系统重定向&#xff0c;以便在运行 32 位应用程序时&#xff0c;可以访问 64 位系统目录。pvoid 是一个指向先前启用的文件系统重定向状态的指针。 构建了要…

《动手学深度学习(PyTorch版)》笔记4.8

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过。…

文本三剑客之grep

目录 一、正则表达式 1、什么是正则表达式 2、元字符 3、扩展正则表达式元字符 二、grep 一、正则表达式 1、什么是正则表达式 REGEXP&#xff1a; Regular Expressions&#xff0c;由一类特殊字符及文本字符所编写的模式&#xff0c;其中有些字符&#xff08;元字符&#…

DevOps落地笔记-04|看板方法:成员工作内容清楚明白方法

上一讲主要介绍了用户故事以及如何通过讲好用户故事解决团队沟通的问题&#xff0c;争取达成共识。当团队都理解了用户需求之后&#xff0c;就进入到后续的产品设计、代码开发、功能测试、直到生产部署等环节了。作为软件从业人员都知道&#xff0c;后续的步骤不太可能一帆风顺…

初探分布式链路追踪

本篇文章&#xff0c;主要介绍应用如何正确使用日志系统&#xff0c;帮助用户从依赖、输出、清理、问题排查、报警等各方面全面掌握。 可观测性 可观察性不单是一套理论框架&#xff0c;而且并不强制具体的技术规格。其核心在于鼓励团队内化可观察性的理念&#xff0c;并确保由…

Python 报错 ERROR: No matching distribution found for xxx

文章目录 1. 报错2. 可能的解决方法3. 参考 1. 报错 例如在安装 Python 包的时候&#xff0c;有时会出现这种情况&#xff1a; ERROR: Could not find a version that satisfies the requirement bokeh (from versions: none) ERROR: No matching distribution found for bok…

人工视觉仍然需要图像采集卡

最初&#xff0c;图像采集卡被用作模拟视频数字转换器和图像缓冲器&#xff0c;但如今它们能够执行复杂的任务&#xff0c;例如图像处理。图像采集卡的设计不断发展&#xff0c;旨在提高系统性能并减少计算机处理需求。 除了图像采集之外&#xff0c;图像采集卡还执行机器视觉…

【正点原子STM32】IWDG 独立看门狗(简介、工作原理、IWDG寄存器配置操作步骤、IWDG溢出时间计算、IWDG配置步骤、独立看门狗流程)

一、IWDG简介 IWDG有什么作用&#xff1f; 二、IWDG工作原理 三、IWDG框图 四、IWDG寄存器 键寄存器&#xff08;IWDG_KR&#xff09;预分频器寄存器 (IWDG_PR)重装载寄存器(IWDG_RLR) 状态寄存器(IWDG_SR) 寄存器配置操作步骤 五、IWDG溢出时间计算 IWDG溢出时间计算公式…