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.hqwc.cn/news/444592.html

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

相关文章

20240127在ubuntu20.04.6下配置whisper

20240131在ubuntu20.04.6下配置whisper 2024/1/31 15:48 首先你要有一张NVIDIA的显卡&#xff0c;比如我用的PDD拼多多的二手GTX1080显卡。【并且极其可能是矿卡&#xff01;】800&#xffe5; 2、请正确安装好NVIDIA最新的驱动程序和CUDA。可选安装&#xff01; 3、配置whispe…

Redis核心技术与实战【学习笔记】 - 10.浅谈CPU架构对Redis性能的影响

概述 可能很多人都认为 Redis 和 CPU 的关系简单&#xff0c;Redis 的线程在 CPU 上运行&#xff0c;CPU 快 Reids 处理请求的速度也很快。 其实&#xff0c;这种认知是片面的&#xff0c;CPU 的多核架构及多 CPU 结构&#xff0c;也会影响到 Redis 的性能。如果不了解 CPU 对…

操作系统基础:进程同步【下】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;OS从基础到进阶 1 进程同步⛵1.1 吸烟者问题✈️1.1.1 问题描述✈️1.1.2 问题分析1.1.2.1 关系分析&#xff08;确定同步、互斥关系&#xff09;1.1.2.2 整理思路&#xff08;确定PV操作的…

Kafka运维相关知识

目录 一、基本概念 二、技术特性 三、设计思想 四、运维建议 一、基本概念 Apache kafka 是一个分布式的基于push-subscribe的消息系统&#xff0c;它具备快速、可扩展、可持久化的特点。它的最大的特性就是可以实时的处理大量数据以满足各种需求场景&#xff1a;比如基于h…

spring cache的使用(Redis)

要在Spring Boot应用中使用Redis作为缓存&#xff0c;你需要遵循一些步骤来配置和使用Redis。以下是使用Spring Cache抽象与Redis进行整合的详细说明&#xff1a; 1. 添加依赖 首先&#xff0c;需要在pom.xml中添加Spring Boot的Redis starter依赖以及缓存的starter依赖。这会…

【web | CTF】攻防世界 easyupload

天命&#xff1a;好像也不太easy 目录 步骤一&#xff1a;准备文件 步骤二&#xff1a;上传文件 本条题目有好几个防御点&#xff1a; 后缀名防御&#xff1a;只能上传图片格式内容防御&#xff1a;内容不能有php图片头防御&#xff1a;检测文件的头部信息&#xff0c;是否是…

【AI大模型应用开发】【附】常用Prompt记录 - 论文全文写作

后面我会不定时更新下我看过的觉得比较好的Prompt&#xff0c;与大家分享&#xff0c;自己也做下记录。 切记&#xff1a;不要全部寄希望于Prompt和大模型能完成你的工作&#xff0c;它的输出天花板&#xff0c;取决于你的认知和能力。你在使用Prompt前&#xff0c;你应该具有对…

如何使用java来操作git/gitlab?

在我们的学习和开发过程中&#xff0c;git作为一个优秀的分布式版本控制工具是经常会被我们使用到的&#xff0c;那么如何通过java代码来实现Git的更新&#xff0c;提交&#xff0c;推送等操作呢&#xff1f;下面整理了三种实现方式&#xff1a; 1.首先我们会想到的应该是寻找市…

2024年【煤炭生产经营单位(安全生产管理人员)】考试题及煤炭生产经营单位(安全生产管理人员)试题及解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 煤炭生产经营单位&#xff08;安全生产管理人员&#xff09;考试题是安全生产模拟考试一点通生成的&#xff0c;煤炭生产经营单位&#xff08;安全生产管理人员&#xff09;证模拟考试题库是根据煤炭生产经营单位&…

Flink实战五_状态机制

接上文&#xff1a;Flink实战四_TableAPI&SQL 在学习Flink的状态机制之前&#xff0c;我们需要理解什么是状态。回顾我们之前介绍的很多流计算的计算过程&#xff0c;有些计算方法&#xff0c;比如说我们之前多次使用的将stock.txt中的一行文本数据转换成Stock股票对象的ma…

某赛通电子文档安全管理系统 PolicyAjax SQL注入漏洞复现

0x01 产品简介 某赛通电子文档安全管理系统(简称:CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护,系统具有透明加密、主动加密、智能…

TypeScript实战教程(一):表单上传与后端处理

TypeScript实战教程&#xff08;一&#xff09;&#xff1a;表单上传与后端处理 文章目录 TypeScript实战教程&#xff08;一&#xff09;&#xff1a;表单上传与后端处理一、前言1、TypeScript介绍2、TypeScript的关键特性包括&#xff1a;3、使用场景4、编译过程 二、环境配置…