基于mmap的读写工具封装案例

文章目录

      • 注意事项
      • C++封装示例
      • 添加构造函数重载以支持追加模式
      • 支持文件大小动态变化
      • 异常安全性和资源泄漏预防
      • 提供更高级的数据访问接口
      • 示例代码改进

在很多高性能应用中,直接使用内存映射文件(mmap)进行文件的读写操作可以显著提高效率,尤其是处理大文件时。以下是一个基于C++的简单封装示例,展示了如何利用 mmap进行文件读写。这个封装旨在提供一个更易用的接口来隐藏底层细节。

注意事项

  • 平台兼容性:本示例主要针对POSIX兼容系统(如Linux、macOS等)。Windows系统有类似的API但实现方式不同。
  • 错误处理:为了保持示例简洁,错误处理相对基础。实际应用中应更全面地处理可能的错误情况,如内存不足、文件不存在等。
  • 资源管理:使用RAII(Resource Acquisition Is Initialization)原则自动管理资源,确保在对象生命周期结束时正确释放资源。

C++封装示例

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <stdexcept>class MmapFile {
public:MmapFile(const std::string& filePath, bool readOnly = true): filePath_(filePath), readOnly_(readOnly) {fd_ = open(filePath.c_str(), readOnly_ ? O_RDONLY : (O_RDWR | O_CREAT), 0644);if (fd_ == -1) {throw std::runtime_error("Failed to open file");}struct stat sb;if (fstat(fd_, &sb) == -1) {close(fd_);throw std::runtime_error("Failed to get file size");}fileSize_ = sb.st_size;data_ = mmap(nullptr, fileSize_, readOnly_ ? PROT_READ : (PROT_READ | PROT_WRITE), MAP_SHARED, fd_, 0);if (data_ == MAP_FAILED) {close(fd_);throw std::runtime_error("Failed to map file");}}~MmapFile() {munmap(data_, fileSize_);close(fd_);}char* data() const {return static_cast<char*>(data_);}size_t size() const {return fileSize_;}// 示例:读取数据std::string readContent() const {return std::string(data_, fileSize_);}// 示例:写入数据(仅当初始化为可写时可用)void writeContent(const std::string& content) {if (!readOnly_) {if (content.size() > fileSize_) {throw std::length_error("Content exceeds file size");}memcpy(data_, content.data(), content.size());// 如果内容变短,这里应有逻辑去截断文件,但为了简化未包含} else {throw std::logic_error("File opened in read-only mode");}}private:int fd_ = -1;char* data_ = nullptr;size_t fileSize_ = 0;std::string filePath_;bool readOnly_;
};int main() {try {// 读取文件示例{MmapFile readFile("example.txt");std::cout << "File content: " << readFile.readContent() << std::endl;}// 写入文件示例(如果文件不存在,会根据O_CREAT创建){MmapFile writeFile("output.txt", false); // 可写模式writeFile.writeContent("Hello, mmap!");}} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return 1;}return 0;
}

这段代码定义了一个MmapFile类,用于封装对文件的内存映射操作。它支持以读或读写模式打开文件,并提供了读取文件内容和写入内容的简单方法。请根据具体需求调整错误处理和功能实现。

为了进一步完善这个封装,我们可以添加一些额外的功能和优化点,使其更加健壮和灵活。下面是一些建议的改进:

添加构造函数重载以支持追加模式

有时候,我们可能希望在现有文件末尾追加内容而不是覆盖原有内容。可以通过在打开文件时使用O_APPEND标志来实现这一点。

支持文件大小动态变化

当前的实现假设文件大小在映射后不会改变。对于可写的映射,如果文件大小需要动态增长或缩小,我们需要额外的逻辑来处理文件截断和重新映射。

异常安全性和资源泄漏预防

确保在构造函数中捕获所有可能的异常,并妥善清理已分配的资源。虽然当前实现已经通过RAII模式管理了大部分资源,但在构造函数中增加详细的错误处理逻辑会更安全。

提供更高级的数据访问接口

例如,添加按行读写、二进制数据读写等功能,使得用户无需直接操作字节指针,提高代码的可读性和易用性。

示例代码改进

考虑到上述建议,这里展示一个简化的追加模式构造函数重载的示例,以及如何处理文件大小变化的思路:

// 追加模式构造函数重载
MmapFile(const std::string& filePath, bool append = false): filePath_(filePath), readOnly_(false) {int flags = O_RDWR | O_CREAT;if (append) flags |= O_APPEND;fd_ = open(filePath.c_str(), flags, 0644);if (fd_ == -1) {throw std::runtime_error("Failed to open file");}// 获取并设置文件大小,对于追加模式,这一步可能不是必须的// 实际应用中可能需要在写入后调整文件大小struct stat sb;if (fstat(fd_, &sb) == -1) {close(fd_);throw std::runtime_error("Failed to get file size");}fileSize_ = sb.st_size;// 注意:对于追加写,直接映射可能不适用,因为映射区域可能不会自动扩展// 实际应用中可能需要在每次写入前手动调整映射区域或使用其他策略data_ = mmap(nullptr, fileSize_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0);if (data_ == MAP_FAILED) {close(fd_);throw std::runtime_error("Failed to map file");}
}// 假设我们想实现一个简单的按行读取方法
std::vector<std::string> readLines() const {std::vector<std::string> lines;const char* ptr = data();const char* end = ptr + size();while (ptr < end) {while (ptr < end && *ptr != '\n') ++ptr;lines.emplace_back(data_, ptr - data_);if (ptr < end) ++ptr; // Skip newline character}return lines;
}// 其他可能的改进,如智能指针包装、更复杂的错误处理等

请注意,对于追加写入,直接使用mmap可能不够直观,因为映射区域通常不会自动增长。在实际应用中,你可能需要在每次写入之前检查和调整映射区域的大小,或者考虑使用其他策略来处理文件增长,比如分块映射或传统的文件I/O结合内存映射。

这些改进点都是为了提升封装类的灵活性、安全性和易用性,具体实现可以根据实际应用场景的需求进行调整。

需要特别注意以下几个核心要点以确保高效、稳定且安全的应用:

  1. 内存页对齐:mmap映射区域的大小必须是物理页大小的整数倍。大多数系统中,页大小通常是4KB。如果不按页对齐,映射可能会失败或导致未预期的行为。

  2. 权限控制:在调用mmap时,需正确设置内存保护标志(如PROT_READ, PROT_WRITE),确保对映射区域的访问权限与预期相符。同时,确保文件描述符在打开时具有相应的读/写权限。

  3. 错误处理:充分考虑并处理所有可能的错误情况,如文件打开失败、内存映射失败、文件大小查询失败等。使用RAII(Resource Acquisition Is Initialization)模式确保资源(如文件描述符)即使在异常情况下也能被正确释放。

  4. 内存同步:当映射区域用于写操作时,需注意内存与磁盘之间的同步问题。可以使用msync()确保修改及时写回磁盘,尤其是在程序退出前或映射解除前,以防止数据丢失。

  5. 文件大小管理:如果映射的文件可能在程序运行期间改变大小,需要实现机制来动态调整映射区域。这通常涉及解映射旧区域、调整文件大小(如使用ftruncate())、然后重新映射。

  6. 并发访问:在多线程或多进程环境中,当多个进程/线程映射同一文件时,需要注意同步和互斥问题,以避免数据竞争和不一致。

  7. 性能考量:虽然mmap可以提高I/O效率,但在小文件或非连续访问模式下可能不如传统I/O高效。评估应用的具体场景,选择合适的读写策略。

  8. 资源限制:考虑系统的资源限制,如地址空间大小、最大文件句柄数等,避免因资源耗尽导致的失败。

  9. 平台兼容性:虽然示例基于POSIX标准,但不同操作系统和内核版本之间可能存在差异。确保代码在目标平台上经过充分测试。

  10. 安全性:确保在处理用户提供的文件路径或数据时进行适当的验证和清理,防止潜在的安全漏洞,如路径遍历攻击。

综合考虑以上要点,可以构建出既高效又可靠的基于mmap的文件读写工具。

😍😍 海量H5小游戏、微信小游戏、Web casualgame源码😍😍
😍😍试玩地址: https://www.bojiogame.sg😍😍
😍看上哪一款,需要源码的csdn私信我😍

————————————————

​最后我们放松一下眼睛
在这里插入图片描述

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

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

相关文章

工业4.0视角下:PLC转OPC UA网关的作用

在工业自动化领域&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;是常见的控制设备&#xff0c;而OPC UA&#xff08;开放型工业自动化统一架构&#xff09;协议则是一种现代化的通信协议&#xff0c;用在工厂自动化系统中实现设备之间的数据交换和通信。PLC转OPC U…

极品AI大模型,抓紧收藏!整合包!

近期&#xff0c;科技巨头谷歌终于发布了1个月前在I/O开发者大会上预告过的Gemma 2大模型。据谷歌介绍&#xff0c;与第1代Gemma模型相比&#xff0c;新模型拥有更优的性能&#xff0c;推理效率也更高。我当然是&#xff0c;“无所谓&#xff0c;我会出手.jpg”&#xff0c;给大…

主数据深度剖析与实际应用

主数据深度剖析与实际应用 想象一下,你正在经营一家跨国连锁咖啡店。每天,全球数千家门店都在使用你的品牌,制作相同的饮品,为客户提供服务。但是,你突然发现一个问题:纽约的"拿铁"和东京的"拿铁"配方似乎不太一样。更糟糕的是,你的线上菜单和实体店菜单显…

最简单的浏览器插件启用github双因素身份验证 (2FA)方法

在github贡献一定的代码量后&#xff0c;github会要求启用双因素身份验证&#xff0c;否则登录会受到影响。一般有短信验证&#xff0c;app扫码验证&#xff0c;这里推荐一种最简单的方式&#xff0c;用浏览器插件验证。 首先&#xff0c;在edge浏览器的微软插件商店&#xff0…

人工智能赋能智慧园区,构建未来城市的科技典范

智慧工地视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。用户只需在界面上…

【免费资料】IEEE33节点系统参数及拓扑图visio

主要内容 对于初学配电网的同学&#xff0c;最经典的系统即是33节点配电网系统&#xff0c;在各个研究文献中出现频次最高的也是这个系统&#xff0c;为了让大家更好了解33节点系统参数&#xff0c;本次整理了系统节点、支路参数excel以及33节点网络拓扑图visio&#xff0c…

20240708 每日AI必读资讯

&#x1f916;破解ChatGPT惊人耗电&#xff01;DeepMind新算法训练提效13倍&#xff0c;能耗暴降10倍 - 谷歌DeepMind研究团队提出了一种加快AI训练的新方法——多模态对比学习与联合示例选择&#xff08;JEST&#xff09;&#xff0c;大大减少了所需的计算资源和时间。 - JE…

探索企业信用巅峰:3A企业认证的魅力与价值

在现代商业环境中&#xff0c;企业的信用和信誉是其发展的核心要素之一。3A企业认证作为信用评级的最高等级&#xff0c;正在吸引越来越多企业的关注。究竟什么是3A企业认证&#xff1f;它为什么对企业如此重要&#xff1f;本文将深入探讨3A企业认证的独特魅力和巨大价值。 3A企…

Oracle AWR报告快速分析工具

一、背景 详细大家都遇到过需要分析Oracle AWR报告的场景&#xff0c;分析AWR对于专业DBA不是什么问题&#xff0c;但是对于一些业务后台研发确实有些困难&#xff0c;很多业务研发人员看的就是条目太多&#xff0c;无从下手。 不过最近我在使用墨天轮浏览国产信创数据库时&am…

面试题 07. 重建二叉树

重建二叉树 题目描述题解原理代码 题目描述 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 题解 原理 代码 TreeNode* build_tree(vector<int> preorder, vector<i…

2.贪心算法.基础

2.贪心算法.基础 基础知识题目1.分发饼干2.摆动序列2.1.思路二&#xff1a;动态规划法 3.最大子序和4.买股票的最佳时机24.1.思路二&#xff1a;动态规划法4.2.买股票的最佳时机 5.跳跃游戏5.1.跳跃游戏2 6.K次取反后最大化的数组和7.加油站8.分发糖果 总结 基础知识 什么是贪…

(三)前端javascript中的数据结构之链表上

在js中&#xff0c;没有为我们提供原生的数据结构支持的&#xff0c;但是在java中是有提供的。所以需要我们去模拟这种结构实现。 链表中最关键的一个元素&#xff0c;就是头节点&#xff0c;头节点不存储数据&#xff0c;指向第一个节点链表中几乎所有的操作都要从头结点开始。…

安全防御(防火墙)

第二天&#xff1a; 1.恶意程序---一般会具有一下多个或则全部特点 1.非法性&#xff1a;你未经授权它自动运行或者自动下载的&#xff0c;这都属于非法的。那恶意程序一般它会具有这种特点&#xff0c; 2.隐蔽性&#xff1a;一般隐藏的会比较深&#xff0c;目的就是为了防止…

Proxifier代理的其他妙用方法(内网渗透、反溯源、小程序公众号)

目录 配置说明 1. 通过Proxifier进行内网渗透 2. 通过Proxifier将VM虚拟机代理 3. 通过Proxifier进行小程序抓包 4. 补充 文章截取处 配置说明 配置其他的之前,要新增一个代理规则,如下: 127.0.0.1; ::1 让它 Direct (直接连接,即不走任何代理)即可 说明: ::1是I…

下一代 CSS 框架:Mojo CSS

前言 Tailwind CSS 推出即受到广大开发者的欢迎&#xff0c;当前 Github star 数已达 77.8k。它是一个功能类优先&#xff08;utility-first&#xff09;的 CSS 框架&#xff0c;它提供了一系列功能类&#xff0c;让开发者可以在 HTML 中通过组合这些功能类&#xff08;原子类…

EPICS数据库示例

本文目标是使用EPICS数据库示例帮助新手理解如何使用不同的示例。 1、使用seq和mbbo的简单选择器 这个简单示例展示了如何使用一个mbbo和一个seq来旋转哪个值将被设置到一个PV。 # 这个mbbo记录将选择将运行seq的哪段 record(mbbo, "CHOOSE") {field(VAL, "…

c#字符串常用方法

目录 1.字符串的处理常用方法 1.1 Format 1.2 IsNullOrEmpty和IsNullOrWhiteSpace 1.3 Equals 1.4 Contains 1.5 Length 1.6 Substring 1.7 IndexOf和LastIndexOf 1.8 ​​​​​​​StartsWith 和 EndsWith 1.9 ​​​​​​​Remove 1.10 ​​​​​​​Revserse…

基于Java+SpringMvc+Vue技术的实验室管理系统设计与实现

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…

如何手工DIV一个小车:基于树莓派和总线舵机的智能小车实现

成品演示&#xff1a;bilibili - 悄悄的魔法书 代码仓库&#xff1a;github - flying forever 或者 gitee - 清风莫追 文章目录 1 引言1.1 课题背景1.2 课题意义1.3 课题目的 2 课题相关知识与开发环境3 课题的总体设计4 课题的详细设计与实现4.1 小车物理结构4.1.1 轮子4.1.2 …

2024年最新ComfyUI汉化及manager插件安装详解!

前言 在ComfyUI文生图详解中&#xff0c;学习过如果想要安装相应的模型&#xff0c;需要到模型资源网站&#xff08;抱抱脸、C站、魔塔、哩布等&#xff09;下载想要的模型&#xff0c;手动安装到ComfyUI安装目录下对应的目录中。 为了简化这个流程&#xff0c;我们需要安装Co…