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.doc
    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;
        }
        // 清除文件状态流的标志
        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函数按字符提取文本内容等,在下一节还会具体介绍。 ↩︎

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

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

相关文章

Flask 入门3:Flask 请求上下文与请求

1. 前言 Flask 在处理请求与响应的过程&#xff1a; 首先我们从浏览器发送一个请求到服务端&#xff0c;由 Flask 接收了这个请求以后&#xff0c;这个请求将会由路由系统接收。然后在路由系统中&#xff0c;还可以挂入一些 “勾子”&#xff0c;在进入我们的 viewFunction …

【C++】开源:Windows图形库EasyX配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Windows图形库EasyX配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#…

✅Redis 常见数据类型和应用场景(详解)

Redis 提供了丰富的数据类型&#xff0c;常见的有五种&#xff1a;String&#xff08;字符串&#xff09;&#xff0c;Hash&#xff08;哈希&#xff09;&#xff0c;List&#xff08;列表&#xff09;&#xff0c;Set&#xff08;集合&#xff09;、Zset&#xff08;有序集合&…

揭开时间序列的神秘面纱:特征工程的力量

目录 写在开头1. 什么是特征工程?1.1 特征工程的定义和基本概念1.2 特征工程在传统机器学习中的应用1.3 时间序列领域中特征工程的独特挑战和需求3. 时间序列数据的特征工程技术2.1 数据清洗和预处理2.1.1 缺失值处理2.1.2 异常值检测与处理2.2 时间特征的提取2.2.1 时间戳解析…

循环——枚举算法2(c++)

目录 找和为K的两个元素 描述 在一个长度为n(n < 1000)的整数序列中&#xff0c;判断是否存在某两个元素之和为k。 输入 第一行输入序列的长度n和k&#xff0c;用空格分开。 第二行输入序列中的n个整数&#xff0c;用空格分开。 输出 如果存在某两个元素的和为k&…

个人建站前端篇(一)项目准备初始化以及远程仓库连接

云风的知识库 云风网前端重构&#xff0c;采用vue3.0vite antd框架&#xff0c;实现前后端分离&#xff0c;实现网站的SEO优化&#xff0c;实现网站的性能优化 vite创建vue项目以及前期准备 Vite 需要 Node.js 版本 18&#xff0c;20。然而&#xff0c;有些模板需要依赖更高…

STM32存储左右互搏 QSPI总线读写FLASH W25QXX

STM32存储左右互搏 QSPI总线读写FLASH W25QXX FLASH是常用的一种非易失存储单元&#xff0c;W25QXX系列Flash有不同容量的型号&#xff0c;如W25Q64的容量为64Mbit&#xff0c;也就是8MByte。这里介绍STM32CUBEIDE开发平台HAL库Qual SPI总线操作W25Q各型号FLASH的例程。 W25Q…

游泳耳机要怎么选购?一篇文章告诉你如何选购游泳耳机

在进行运动时享受音乐的乐趣是许多人的喜好&#xff0c;对于在地面展开的一般运动&#xff0c;选择耳机相对简单&#xff0c;但若是涉及水中游泳&#xff0c;我们就需要一款具备防水性能的专业游泳耳机。市面上已有数款针对游泳设计的防水耳机&#xff0c;本文将为您详细介绍如…

【解刊】审稿人极其友好!中科院2区SCI,3个月录用,论文质量要求宽松!

计算机类 • 高分快刊 今天带来Springer旗下计算机领域高分快刊&#xff0c;有投稿经验作者表示期刊审稿人非常友好&#xff0c;具体情况一起来看看下文解析。如有投稿意向可重点关注&#xff1a; 01 期刊简介 Complex & Intelligent Systems ✅出版社&#xff1a;Sprin…

光杆司令如何部署大模型?

1、背景 今天这种方式非常贴合低配置笔记本电脑的小伙伴们, 又没有GPU资源, 可以考虑使用api方式,让模型服务厂商提供计算资源 有了开放的api,让你没有显卡的电脑也能感受一下大模型管理知识库,进行垂直领域知识的检索和问答.算是自己初步玩一下AI agent 之前有写过一篇《平民…

Java二维码图片识别

前言 后端识别二维码图片 代码 引入依赖 <dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.2.1</version></dependency><dependency><groupId>com.google.zxing<…

软件压力测试:探究其目的与重要性

随着软件应用在各行各业中的广泛应用&#xff0c;确保软件在高负载和极端条件下的稳定性变得至关重要。软件压力测试是一种验证系统在不同负载条件下的性能和稳定性的方法。本文将介绍软件压力测试的目的以及为什么它对软件开发和部署过程至关重要。 验证系统性能的极限&#x…

二、人工智能之提示工程(Prompt Engineering)

黑8说 岁月如流水匆匆过&#xff0c;哭一哭笑一笑不用说。 黑8自那次和主任谈话后&#xff0c;对这个“妖怪”继续研究&#xff0c;开始学习OpenAI API&#xff01;关注到了提示工程(Prompt Engineering)的重要性&#xff0c;它包括明确的角色定义、自然语言理解&#xff08;…

10个关键字让你的谷歌竞价排名瞬间飙升-华媒舍

在现代社会中&#xff0c;搜索引擎已经成为获取信息的主要途径之一。在这其中&#xff0c;谷歌搜索引擎以其强大的搜索算法和智能化的用户体验而闻名。对于企业主来说&#xff0c;如何提高在谷歌搜索结果中的排名&#xff0c;对于他们的品牌推广和获取潜在客户非常重要。 1. 关…

springboot137欢迪迈手机商城设计与开发

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

Shell脚本——免交互

目录 一、Here Document免交互 1、免交互概述 2、语法格式 2.1示例&#xff1a;免交互方式实现对行数的统计&#xff0c;将要统计的内容置于标记EOF之间&#xff0c;直接将内容传给wc-l来统计 3、变量设定 ①变量图换成实际值 ②整行内容作为变量并输出结果 ③使输出内…

二、图像色彩空间转换

一、色彩空间头文件 在项目的头文件中&#xff0c;右击添加&#xff0c;新建项 例如我的是testopencv.h 自定义一个头文件&#xff0c;用于图片色彩空间的转换和保存操作 定义个Colors类 里面有一个函数声明void colorspaces(Mat& image);&#xff0c;用于实现图片的色…

第九节HarmonyOS 常用基础组件22-Marquee

1、描述 跑马灯组件&#xff0c;用于滚动展示一段单行文本&#xff0c;仅当文本内容宽度超过跑马灯组件宽度时滚动。 2、接口 Marquee(value:{start:boolean, step?:number, loop?:number, fromStart?: boolean ,src:string}) 3、参数 参数名 参数类型 必填 描述 st…

SparkStreaming---入门

文章目录 1.SparkStreaming简介1.1 流处理和批处理1.2 实时和离线1.3 SparkStreaming是什么1.4 SparkStreaming架构图 2.背压机制3.DStream案例实操 1.SparkStreaming简介 1.1 流处理和批处理 流处理和批处理是两种不同的数据处理方式&#xff0c;它们在处理数据的方式和特点…

【Midjourney】AI绘画案例(1)龙年吉祥神兽

说明&#xff1a; 1、文中图片版权均为Midjourney所有&#xff0c;请勿用作商业用途。 2、文中图片均经过 Upscale x 4 处理。 3、由于模型原因&#xff0c;某些图片存在暇玼。 1、吉祥神兽——天马&#xff08;独角兽&#xff09; 天马消灾星。 提示词 Prompt: Sky Unicor…