C++文件操作(2)

文件操作(2)

  • 1.二进制模式读取文本文件
  • 2.使用二进制读写其他类型内容
  • 3.fstream类
  • 4.文件的随机存取
    • 文件指针的获取
    • 文件指针的移动

1.二进制模式读取文本文件

用二进制方式打开文本存储的文件时,也可以读取其中的内容,因为文本文件本质上是存储字符类型数据。这种方式读取文件内容我们需要用到string类型的方法:

int main()
{ifstream mytest("test.txt",ios::in|ios::binary); // ios::in是默认参数,可以不写if(mytest.is_open()){cout<<"打开文件失败"<<endl;return 0;}// 二进制文件读取后需要用正确的接收格式接收// string out((istreambuf_iterator<char>(mytest)), (istreambuf_iterator<char>())) // 直接使用string的构造函数对out进行赋值string out;out.assign((istreambuf_iterator<char>(mytest)), (istreambuf_iterator<char>())); // 使用assign函数赋值cout<<out;// 关闭文件mytest.close();
}

istreambuf_iterator会迭代访问文件内容,读取完成后out会存贮整个文件的内容,不需要一行一行读取:
在这里插入图片描述

2.使用二进制读写其他类型内容

有时候我们也需要借由二进制模式处理一些非文本形式的简单数据,比如数字数组。这样的类型处理方法和上一节用结构体类型读写二进制文件很相似:

int main()
{ofstream mytest("nums.txt",ios::app|ios::binary); // 读取二进制文件if(mytest.is_open()){// 二进制文件读取后需要用正确的接收格式接收int numbers[]={10,15,20,30,55,67};mytest.write(reinterpret_cast<const char*>(numbers),sizeof(numbers));}else{cout<<"打开文件失败"<<endl;return 0;}// 关闭文件mytest.close();
}

这里我们将一个整形数组以二进制形式写成了二进制文件,这里的reinterpret_cast<const char*>(numbers)是C++指针类型的强制转换,等同于(const char*)numbers。
当我们想要读取时,也用类似的办法处理。值得注意的是,如果我们知道数组的具体大小,读取内容的任务又会简单许多:

int main()
{ifstream mytest("nums.txt",ios::in|ios::binary);if(mytest.is_open()){int numbers[6];mytest.read(reinterpret_cast<char*>(numbers), sizeof(numbers));// 查看内容是否正确存储到整形数组里for(int i=0;i<=5;i++){cout<<numbers[i]<<" ";}}else{cout<<"打开文件失败"<<endl;return 0;}// 关闭文件mytest.close();
}
// 输出为:10 15 20 30 55 67 

如果换成长度已知的结构体数组,也可以这样处理。
如果我们不知道数组的具体长度,也可以一个一个读出文件的存储内容:

 int main()
{ifstream mytest("nums.txt",ios::in|ios::binary); // 读取二进制文件if(mytest.is_open()){int number;while(mytest.read((char*)&number,sizeof(int))){cout<<number<<" ";}}else{cout<<"打开文件失败"<<endl;return 0;}// 关闭文件mytest.close();
}

输出结果同上例一样。

3.fstream类

在C语言中,文件操作只有文件指针,没有输入输出流的区别,C++是在C基础上将输入和输出分别封装成类,ifstream类用于读文件,ofstream用于写入文件。但是C++也保留了同时可以完成读写的类:fstream。它的使用方法与ifstream和ofstream完全相似,如果我们想写如文件:

int main()
{fstream mytest("test.txt"); if(mytest.is_open()){mytest<<"这是另一个测试\n";}else{cout<<"打开文件失败"<<endl;return 0;}// 关闭文件mytest.close();
}

如果我们想读取文件:

int main()
{fstream mytest("test.txt"); if(mytest.is_open()){string out;while(mytest>>out){cout<<out<<endl;}}else{cout<<"打开文件失败"<<endl;return 0;}// 关闭文件mytest.close();
}
// 输出为:这是一个测试
//        我们尝试连续输入内容
//        继续测试这是一个测试
//        我们尝试连续输入内容
//        这是一个测试
//        我们尝试连续输入内容
//        这是另一个测试

我们以打开文本文件为例,展示了fstream类用法,操作二进制文件的方法也可以直接照搬ifstream和ofstream类。但是fstream仍有一些细节需要我们注意,fstream类的默认写参数是ios::out和ios::in,至于具体执行那种操作会根据后面的代码进行确定。写入文件时默认参数ios::out参数在没有文件时会创建文件,但再有文件时是默认在文件最后写内容,类似于ios::app。fstream打开文件时还有一些参数可供使用:

ios::ate 以定位到文件末尾的方式打开文件
ios::in|ios::out 以读写方式打开文件
ios::out|ios::truct 如果文件存在,则截断文件重新写入内容,类似于ofstream类的out模式。

通常情况下,规范的编程通常在需要写文件的时候使用ofstream,需要读的时候用ifstream,即需要读又需要写的时候再使用fstream类。在Linux平台下,读和写有严格的权限控制,为了方便管理,我们调用的权限应当尽量少。举个例子,如果我们只需要读取文件,那么即使我们有读写的权限,也应当以只读方式打开文件。

4.文件的随机存取

之前我们介绍了文件的写入都是在文件的末尾或删除文件内容后再写入内容,而读文件都是从文件的开头进行的。这是因为读写文件都是从文件位置指针1处开始的,我们之前的操作文件的方式,文件指针都会在文件的最开始或最末尾。实现文件的随机存取,关键就在于调整文件指针所在位置。

文件指针的获取

获取文件指针位置的方法,输入流ofstream类为成员函数是 tellp();输出流ifstream类为成员函数是 tellg();fstream类两个成员函数都有且效果完全相同。以写文件为例:

int main()
{ofstream mytest("test1.txt",ios::app); if(mytest.is_open()){cout<<mytest.tellp()<<endl;mytest<<"以写入文本为例\n";cout<<mytest.tellp()<<endl;}else{cout<<"打开文件失败"<<endl;return 0;}// 关闭文件mytest.close();
}
// 输出为:0
//        22

读取文件同时获取文件指针的方法与写入相同:

// Student结构体上节内容中有所定义
int main()
{ifstream mytest("test.doc",ios::app|ios::binary); if(mytest.is_open()){cout<<mytest.tellg()<<endl;Student child;while(mytest.read((char*)&child,sizeof(child))){cout<<child.name<<" "<<child.age<<" "<<child.sex<<endl;cout<<"mytest.tellg()="<<mytest.tellg()<<endl;}}else{cout<<"打开文件失败"<<endl;return 0;}// 关闭文件mytest.close();
}
// 输出为:0
// 		  ZhangSan 15 m
//		  mytest.tellg()=40
//		  LiSi 20 m
//		  mytest.tellg()=80

可以看到,在二进制文件中获取文件指针位置的方法与文本文件相同。此外,给大家说个冷知识,使用ios::app打开文件除了可以在文件末尾追加内容,也可以用于读取文件信息,文件指针位置会根据任务自动进行调整。不过为了规范编程尽量不要这样乱用。
fstream类在这里就不做展示了,用法完全相同大家可以自行尝试。

PS:文件只有一个位置指针,并非同时拥有读指针和写指针。

文件指针的移动

文件的读和写都是在当前文件指针的位置往后进行的,也就是说如果我们能够移动文件的位置指针就可以做到调整读写数据的位置。C++中为我们提供了这样的方法,ifstream类使用seekg()成员函数移动文件指针,ofstream类使用seekp()成员函数移动文件指针,fstream类依旧是两者都可用,效果相同。
seekp和seekg有两个常用的重载,第一种为:

seekg(ios::beg) 将文件指针移动到0位置
seekg(ios::end) 将文件指针移动到末尾
seekg(128) 将文件指针移动到指定位置,这里指定文件指针移动到128位置
注:将seekg换成seekp效果完全类似

我们看个例子:

int main()
{ifstream mytest("test.txt",ios::in); if(mytest.is_open()){mytest.seekg(29);cout<<mytest.tellg()<<endl;string out;while(mytest>>out){cout<<out<<" "<<"当前位置为:"<<mytest.tellg()<<endl;}}else{cout<<"打开文件失败"<<endl;return 0;}mytest.close();
}

输出结果为:
在这里插入图片描述
另外需要注意,由于一个中文占3个字节,因此我需要注意文件指针所在位置不能在某个中文字的内部。假如使用mytest.seekg(28),输出内容就会出现异常。
另一种常用seek方法的重载有两个参数:

seekg(10,ios::beg) 文件指针从0位置开始向后移动10字节
seekg(-3,ios::end) 文件指针从末尾开始向前移动3字节
seekg(5,ios::cur) 文件指针从当前位置开始向后移动5字节
注:将seekg换成seekp效果完全类似

还是看个例子:

// student类与test.doc文化部在上节中已经定义和创建
int main()
{fstream mytest("test.doc",ios::in | ios::out | ios::binary ); // 使用读写模式打开二进制文件test.docif(mytest.is_open()){cout<<mytest.tellg()<<endl;Student child;while(mytest.read((char*)&child,sizeof(child))){cout<<child.name<<" "<<child.age<<" "<<child.sex<<endl;cout<<"mytest.tellg()="<<mytest.tellg()<<endl;}// 清除文件状态流的标志mytest.clear();cout<<"\n以上内容作为对比\n"<<endl;mytest.seekg(-40,ios::cur);child=Student{"WangWu",22,'w'};mytest.write((const char*)&child,sizeof(Student));mytest.seekg(ios::beg);while(mytest.read((char*)&child,sizeof(child))){cout<<child.name<<" "<<child.age<<" "<<child.sex<<endl;cout<<"mytest.tellg()="<<mytest.tellg()<<endl;}mytest.close();}else{cout<<"打开文件失败"<<endl;return 0;}
}

在这段代码中,大家可能会不理解mytest.clear()的用意,在我们使用while循环读取文件的全部内容后,failbite会被设置为true2,这标志会让计算机认为文件遇到错误,后面就无法正常对文件进行操作了。使用clear函数可以清除这些标志,后面才能继续操作文件。
输出是这样的:
在这里插入图片描述
可以看到我们虽然移动了文件指针,在再定位置添加了内容,但是原有的内容却是被覆盖掉了。如果我们想要保留原来的内容,需要将插入位置后面的内容向后移动若干单位,实现方法类似于在数组中插入一个数。

本节我们继续学习了C++操作文件的方法,其中,改变文件指针的位置是我们学习的重点。在实际应用中,我们经常会遇到需要从指定位置读取和写入内容的任务,希望大家能够掌握本节内容。


  1. 在C++中,文件位置指针的指向就是文件中进行读取或写入操作时的初始位置。 ↩︎

  2. 除了我们用过的方法(如is_open())外,文件流还有很多比较实用的方法,如使用eof()方法判断是否到达文件末尾,使用good函数判断文件写入是否成功,使用get函数按字符提取文本内容等,在下一节还会具体介绍。 ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ快速上手

首先他的需求实在什么地方。我美哟明显的感受到。 它给我的最大感受就是脱裤子放屁——多此一举&#xff0c;的感觉。 他将信息发送给服务端中间件。在由MQ服务器发送消息。 服务器会监听消息。 但是它不仅仅局限于削峰填谷和稳定发送信息的功能&#xff0c;它还有其他重要…

15.Golang中的反射机制及应用

目录 概述实践基本应用复杂应用 结束 概述 Golang中的反射用法还是比较简单的 reflect.TypeOf(arg)reflect.ValueOf(arg) 实践 基本应用 package mainimport ("fmt""reflect" )func reflectNum(arg interface{}) {fmt.Println("type ", re…

十分钟快速上手Spring Boot与微信小程序API接口的调用,快速开发小程序后端服务

1.1 微信小程序API接口介绍 微信小程序API接口是连接小程序前端与后端服务器的桥梁&#xff0c;它提供了丰富的功能接口&#xff0c;包括用户信息、支付、模板消息、数据存储等。这些API接口能够满足开发者在小程序中实现各种复杂业务逻辑的需求。 用户信息接口 用户信息接口…

全流程机器视觉工程开发(四)PaddleDetection C++工程化应用部署到本地DLL以供软件调用

前言 我们之前跑了一个yolo的模型&#xff0c;然后我们通过PaddleDetection的库对这个模型进行了一定程度的调用&#xff0c;但是那个调用还是基于命令的调用&#xff0c;这样的库首先第一个不能部署到客户的电脑上&#xff0c;第二个用起来也非常不方便&#xff0c;那么我们可…

【C++干货基地】C++引用与指针的区别:深入理解两者特性及选择正确应用场景

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

MYSQL的配置和安装

下载安装 打开官网 MYSQL官网 点击DOWNLOADS 滑到最低下点击&#xff1a;MYSQL Community(GPL) Downlads 点击Download Archives 点击MySQL Community Server进入网站 选择相应版本下载&#xff0c;这里选择的是5.7.24版本,x86 64位【按需选择】 下载解压 配置文件…

GitLab16.8配置webhooks、Jenkins2.4配置GitLab插件实现持续集成、配置宝塔面板实现持续部署(其三)

看本篇文章的前提是已经部署完GItlab和Jenkins服务器&#xff0c;已经可以手动构建成功&#xff0c;并且经过了很多次实践&#xff0c;对这两款软件基本熟悉。 建议大家按以下顺序看 前端自动化&#xff08;其一&#xff09;部署gitlab 前端自动化&#xff08;其二&#xff0…

LeetCode--171

171. Excel 表列序号 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 示例 1: 输入: columnTitle "A" 输出:…

设计模式⑩ :用类来实现

文章目录 一、前言二、Command 模式1. 介绍2.应用3. 总结 三、Interpreter 模式1. 介绍2. 应用3. 总结 参考文章 一、前言 有时候不想动脑子&#xff0c;就懒得看源码又不像浪费时间所以会看看书&#xff0c;但是又记不住&#xff0c;所以决定开始写"抄书"系列。本系…

【JS逆向实战-入门篇】某gov网站加密参数分析与Python算法还原

文章目录 1. 写在前面2. 请求分析3. 断点分析4. 算法还原 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋…

PPT、PDF全文档翻译相关产品调研笔记

主要找一下是否有比较给力的全文档翻译 文章目录 1 百度翻译2 小牛翻译3 腾讯交互翻译4 DeepL5 languagex6 云译科技7 快翻:qtrans8 simplifyai9 officetranslator10 火山引擎翻译-无文档翻译1 百度翻译 地址: https://fanyi.baidu.com/ 配套的比较完善,对于不同行业也有区…

【大厂AI课学习笔记】1.3 人工智能产业发展(2)

&#xff08;注&#xff1a;腾讯AI课学习笔记。&#xff09; 1.3.1 需求侧 转型需求&#xff1a;人口红利转化为创新红利。 场景丰富&#xff1a;超大规模且多样的应用场景。主要是我们的场景大&#xff0c;数据资源丰富。 抗疫加速&#xff1a;疫情常态化&#xff0c;催生新…

DataX介绍

一、介绍 DataX 是一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 github地址 详细文档 操作手册 支持数据框架如下&#xff1a; 架构 Reader&#xff1…

干货!收藏!一文讲清楚数据治理到底是什么?

数据治理的两个目标&#xff1a;一个是提质量&#xff0c;一个是控安全。通过业务流程优化&#xff0c;规范数据从产生、处理、使用到销毁的整个生命周期&#xff0c;使得数据在各阶段、各流程环节安全可控&#xff0c;合规使用。 数据治理治的是“数据”吗&#xff1f; 数据是…

Ubuntu搭建国标平台wvp-GB28181-pro

目录 简介安装和编译1.查看操作系统信息2.安装最新版的nodejs3.安装java环境4.安装mysql5.安装redis6.安装编译器7.安装cmake8.安装依赖库9.编译ZLMediaKit9.1.编译结果说明 10.编译wvp-GB28181-pro10.1.编译结果说明 配置1.WVP-PRO配置文件1.1.Mysql数据库配置1.2.REDIS数据库…

GPT-5的功能界面曝光。。。

最近网络上流传的照片是否真实尚不可知&#xff0c;我们需要进一步的核实与分析。 GPT-5的预期发布已经引起了业界的极大关注。根据Roemmele的透露&#xff0c;GPT-5将是一个革命性的多模态模型&#xff0c;能够支持语音、图像、编程代码和视频等多种格式&#xff0c;这标志着…

【Linux】多线程(线程概念+线程控制)

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

负载均衡下的webshell上传+nginx解析漏洞

负载均衡下的webshell上传 一&#xff0c;负载均衡下webshell上传的四大难点 难点一&#xff1a;需要在每一台节点的相同位置上传相同内容的webshell 我们需要在每一台节点的相同位置都上传相同内容的 WebShell一旦有一台机器上没有&#xff0c;那么在请求轮到这台机器上的时…

二分查找-迭代法

Go 算法 每天5道&#xff0c;开心快乐每一天 一点都不开心 哈哈哈哈哈哈 -2.1 day 1 1.22&#xff08;1.23 1.25 1.29&#xff09; 1.23 已复习 704. 二分查找 力扣题目链接 //左闭右开 func search(nums []int, target int) int { right : len(nums) left : 0; for le…

React18-模拟列表数据实现基础表格功能

文章目录 分页功能分页组件有两种接口参数分页类型用户列表参数类型 模拟列表数据分页触发方式实现目录 分页功能 分页组件有两种 table组件自带分页 <TableborderedrowKey"userId"rowSelection{{ type: checkbox }}pagination{{position: [bottomRight],pageSi…