c++ - 在 Linux 与 Windows 上读取大文件(mmap 与 CreateFileMapping/MapViewOfFile)
问题描述
我必须从一个大文件(超过 7GB)中逐行读取一些数据,它包含顶点坐标列表和面到顶点连接信息以形成网格。我也在学习如何在 Linux 和Windows上使用open
, 。Linux 和 Windows 版本都是 64 位编译的。mmap
CreateFileA
CreateFileMapping
MapViewOfFile
当我在 Linux(使用 docker)上时,g++-10 test.cpp -O3 -std=c++17
我得到了大约 6 秒。当我在 Windows(我的实际 PC)上使用(版本 19.29.30037 x64)cl test.cpp /EHsc /O3 /std:c++17
时,我得到 13s,使用clang++-11
(来自 Visual Studio Build Tools)我得到 11s。
两个系统(同一台 PC,但一个使用 docker)使用相同的确切代码,除了生成const char*
表示内存阵列和表示uint64_t
内存大小的大小。
这是我切换平台的方式:
// includes for using a specific platform API
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// using windows handle void*
#define handle_type HANDLE
#else
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
// using file descriptors
#define handle_type int
#endif
具体来说,在 char-s 数组中获取内存的代码是:
using uint_t = std::size_t;
// open the file -----------------------------------------------------------------------------
handle_type open(const std::string& filename) {
#ifdef _WIN32
// see windows file mapping api for parameter explanation
return ::CreateFileA(filename.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // private access
#else
return ::open(filename.c_str(), O_RDONLY);
#endif
}
// get the memory size to later have a bound for reading -------------------------------------
uint_t memory_size(handle_type fid) {
#ifdef _WIN32
LARGE_INTEGER size{};
if (!::GetFileSizeEx(fid, &size)) {
std::cerr << "file not found\n";
return size.QuadPart;
}
return size.QuadPart;
#else
struct stat sb;
// get the file stats and check if not zero size
if (fstat(fid, &sb)) {
std::cerr << "file not found\n";
return decltype(sb.st_size){};
}
return sb.st_size;
#endif
}
// get the actual char array to access memory ------------------------------------------------
const char* memory_map(handle_type fid, uint_t memory_size) {
#ifdef _WIN32
HANDLE mapper = ::CreateFileMapping(fid, NULL, PAGE_READONLY, 0, 0, NULL);
return reinterpret_cast<const char*>(::MapViewOfFile(mapper, FILE_MAP_READ, 0, 0, memory_size));
#else
return reinterpret_cast<const char*>(::mmap(NULL, memory_size, PROT_READ, MAP_PRIVATE, fid, 0));
#endif
}
我对这种解析完全陌生,想知道我在选择 Windows API 中的参数时是否做错了(模仿 mmap 的行为),或者时间差异是否与编译器/系统有关,必须接受?
在 Linux 和 Windows 上,打开、获取内存大小和内存映射的实际时间可以忽略不计,其余代码是相同的,因为它只使用const char*
和size_t
信息进行操作。
感谢您花时间阅读。非常感谢任何提示,如果有任何不清楚的地方,我们深表歉意。
解决方案
也许你应该看看https://github.com/alitrack/mman-win32这是 Windows 的 mmap 实现。这样您就不需要为 Windows 编写不同的代码。
推荐阅读
- r - 使用 R 中的 pivot_wider() 使用 values_fn 执行聚合(例如求和、平均值)时出错
- php - 尝试使用 mysql db 中的时间戳时 PHP date_create 失败
- android - Kotlin NullPointerException 问题
- php - 如何计算数组中的文本?
- c++ - Visual Studio Code:CMake 工具选项卡中的文件路径不正确
- c++ - 从矢量中擦除
- java - 如何以并行模式运行有序的 JUnit5 测试
- python - 通过 crontab 运行烧瓶命令
- r - 如何使用某些定义的逻辑根据特定日期范围及其价值查找每周二
- python - 可视化层输出时出现 Keras(带有 Tensorflow 2 后端)错误