C++文件操作(2)

news2024/9/27 23:30:19

文件操作(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函数按字符提取文本内容等,在下一节还会具体介绍。 ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通过WSL2来实现Windows10/11的深度学习模型GPU加速,TensorFlow项,Jupyter及其插件安装,CQF心得,金融量化

通过WSL2来实现TF的GPU加速 为什么要用WSL&#xff08;Windows Subsystem Linux&#xff09;安装WSL2&#xff0c;miniconda&#xff0c;cuda&#xff0c;cudnn&#xff0c;TA-Lib安装 WSL2安装 Miniconda3安装 CUDA安装 cuDNN安装 TensorFlow 库安装 TA-Lib 库安装其它CQF及金…

MySQL-----DML基础操作

DML语句 DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进行增删改操作。 ▶ 添加数据(INSERT) 【语法】 1. 给指定字段添加数据 INSERTO 表名 (字段名1&#xff0c;字段名2,...) VALUES (值1&#xff0c;值2,...); 2.给全…

获取真实 IP 地址(二):绕过 CDN(附链接)

一、DNS历史解析记录 DNS 历史解析记录指的是一个域名在过去的某个时间点上的DNS解析信息记录。这些记录包含了该域名过去使用的IP地址、MX记录&#xff08;邮件服务器&#xff09;、CNAME记录&#xff08;别名记录&#xff09;等 DNS 信息。DNS 历史记录对于网络管理员、安全研…

跟着cherno手搓游戏引擎【19】抽象纹理

引入&#xff1a; 导入stb_image: GitHub - nothings/stb: stb single-file public domain libraries for C/C 下载复制stb_image.h的内容&#xff08;8000多行&#xff09;&#xff0c;然后粘到如图位置 stb_image.cpp: #include"ytpch.h" #define STB_IMAGE_IM…

LabVIEW叶片厚度远程监控

LabVIEW叶片厚度远程监控 随着网络技术的高速发展&#xff0c;远程监控广泛应用在各个领域。本文介绍了一种基于LabVIEW的植物叶片厚度远程监控系统&#xff0c;旨在实现对植物生长状况的精准监测和分析。 该系统利用LabVIEW软件开发工具&#xff0c;通过TCP网络协议实现数据…

抖音协议算法

以下是一些可能存在于社交媒体平台算法中的常见组成部分&#xff1a; 1. 用户兴趣模型&#xff1a;平台会根据用户的行为、喜好、关注的话题等信息&#xff0c;构建用户的兴趣模型。这可以通过分析用户的观看历史、点赞、评论、分享等行为来实现。 2. 内容特征提取&#xff1…

node.js基础--01

Author nodes&#xff1a;&#xff08;题记&#xff09; node.js is an open-source&#xff0c;cross-platform JAVAScript runtime environment。 node.js是一个开源&#xff0c;跨平台的js运行环境 common commands&#xff08;常用指令&#xff09; 1、C: enter hard …

C语言第十七弹---指针(一)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、内存和地址 1.1、内存 2、指针变量和地址 2.1、取地址操作符&#xff08;&&#xff09; 2.2、指针变量和解引用操作符&#xff08;*&#xff09;…

短剧小程序开发:打造高效、便捷的娱乐体验

随着移动互联网的普及和用户需求的多样化&#xff0c;短剧小程序作为一种新型的应用形态&#xff0c;逐渐受到了广大用户的青睐。短剧小程序开发旨在为用户提供一种高效、便捷的娱乐体验&#xff0c;让用户在忙碌的生活中轻松享受到精彩的短剧内容。本文将探讨短剧小程序开发的…

基于ssm的运动会管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

Java玩转《啊哈算法》解密QQ号之队列

行有不得&#xff0c;反求诸己 文章目录 开头代码地址引子案例分析代码 队列封装升级演示 开头 各位好&#xff01;本人在看《啊哈算法》&#xff0c;写的确实不错。 但略微遗憾的是&#xff0c;书籍示例代码是c语言&#xff0c;不是本人常用的Java。 那就弥补遗憾&#xff…

Linux 系统开始配置

文章目录 备份源为root 设置密码安装基本工具切换root 用户删除snap从 Ubuntu 移除 Snap 后使用 deb 文件安装软件商店和 Firefox在 Ubuntu 系统恢复到 Snap 软件包总结 删除 vim安装neovim在线安装neovim压缩安装neovim安装lazyvim安装剪切板 安装qt配置 Qt 环境不在sudoers文…

Flutter 仿抖音 TikTok 上下滑动 播放视频

Flutter 仿抖音 TikTok 上下滑动 播放视频UI框架&#xff0c;视频播放使用 video_player github&#xff1a;GitHub - PangHaHa12138/TiktokVideo: Flutter 仿抖音 TikTok 上下滑动 播放视频UI框架 实现功能&#xff1a; 1.上下滑动自动播放切换视频&#xff0c;loading 封面…

帮管客CRM 文件上传漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

Linux实验记录:使用vsftpd服务传输文件

前言&#xff1a; 本文是一篇关于Linux系统初学者的实验记录。 参考书籍&#xff1a;《Linux就该这么学》 实验环境&#xff1a; VmwareWorkStation 17——虚拟机软件 RedHatEnterpriseLinux[RHEL]8——红帽操作系统 备注&#xff1a; 为了解决在多样复杂的设备之间解决传…

阿狸与小兔子的奇幻之旅

在很久很久以前&#xff0c;有一个遥远的国度&#xff0c;这个国度里生活着各种各样的动物&#xff0c;它们和谐共处&#xff0c;幸福快乐。在这个国度里&#xff0c;有一只聪明伶俐的小狐狸&#xff0c;名叫阿狸。 一天&#xff0c;阿狸在森林里散步时&#xff0c;遇到了一只正…

C++类和对象入门(二)

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、类的作用域 类定义了一个新的作用域&#xff0c;类的所有成员都在类的作用域中。在类体外定义成员时&#xff0c;需要…

亚马逊测评掉评、留不上评:问题根源与解决之道

亚马逊作为全球最大的电商平台之一&#xff0c;拥有数亿活跃用户和数百万卖家。在这个竞争激烈的市场中&#xff0c;产品评价对于卖家的成功至关重要。然而&#xff0c;许多卖家在尝试通过测评获取好评时&#xff0c;却遇到了掉评、留不上评的问题&#xff0c;这无疑增加了他们…

安装配置sqoop

一、了解Sqoop 1、Sqoop产生的原因 A. 多数使用hadoop技术的处理大数据业务的企业,有大量的数据存储在关系型数据中。 B. 由于没有工具支持,对hadoop和关系型数据库之间数据传输是一个很困难的事。 以上是sqoop产生的主要原因,也因此Sqoop主要用于hadoop与关系型数据库之…

如何在docker中访问电脑上的GPU?如何在docker中使用GPU进行模型训练或者加载调用?

如何在docker中访问电脑上的GPU&#xff1f;如何在docker中使用GPU进行模型训练或者加载调用&#xff1f; 其实使用非常简单&#xff0c;只是一行命令的事&#xff0c;最主要的事配置好驱动和权限。 docker run -it --rm --gpus all ycj520/centos:1.0.0 nvidia-smi先看看 st…