c++ - 读取二进制文件的惯用 C++17 标准方法是什么?
问题描述
通常我只会使用 C 样式文件 IO,但我正在尝试现代 C++ 方法,包括使用 C++17 特定功能std::byte
和std::filesystem
.
将整个文件读入内存,传统方法:
#include <stdio.h>
#include <stdlib.h>
char *readFileData(char *path)
{
FILE *f;
struct stat fs;
char *buf;
stat(path, &fs);
buf = (char *)malloc(fs.st_size);
f = fopen(path, "rb");
fread(buf, fs.st_size, 1, f);
fclose(f);
return buf;
}
将整个文件读入内存,现代方法:
#include <filesystem>
#include <fstream>
#include <string>
using namespace std;
using namespace std::filesystem;
auto readFileData(string path)
{
auto fileSize = file_size(path);
auto buf = make_unique<byte[]>(fileSize);
basic_ifstream<byte> ifs(path, ios::binary);
ifs.read(buf.get(), fileSize);
return buf;
}
这看起来对吗?这可以改进吗?
解决方案
除非您正在阅读实际的文本文档,否则我个人更喜欢std::vector<std::byte>
使用。std::string
问题make_unique<byte[]>(fileSize);
是您会立即丢失数据的大小,并且必须将其放在单独的变量中。std::vector<std::byte>
它可能比它不会零初始化的给定速度快一小部分。但我认为这可能总是被从磁盘读取所花费的时间所掩盖。
所以对于一个二进制文件,我使用这样的东西:
std::vector<std::byte> load_file(std::string const& filepath)
{
std::ifstream ifs(filepath, std::ios::binary|std::ios::ate);
if(!ifs)
throw std::runtime_error(filepath + ": " + std::strerror(errno));
auto end = ifs.tellg();
ifs.seekg(0, std::ios::beg);
auto size = std::size_t(end - ifs.tellg());
if(size == 0) // avoid undefined behavior
return {};
std::vector<std::byte> buffer(size);
if(!ifs.read((char*)buffer.data(), buffer.size()))
throw std::runtime_error(filepath + ": " + std::strerror(errno));
return buffer;
}
这是我所知道的最快的方法。它也避免了在确定文件中数据大小时的常见错误,因为ifs.tellg()
不一定与打开文件末尾的文件大小相同,ifs.seekg(0)
理论上也不是定位文件开头的正确方法(即使它在大多数地方都适用)。
来自的错误消息std::strerror(errno)
保证可以在POSIX
系统上运行(应该包括 Microsoft,但不确定)。
显然,您可以根据std::filesystem::path const& filepath
需要使用std::string
。
此外,特别是对于 pre C++17
,您可以使用std::vector<unsigned char>
,或者std::vector<char>
如果您没有或不想使用std::byte
.
推荐阅读
- php - 如何创建一个静态变量并从另一个类调用它?
- github-pages - 如何使用 github 页面中的 2 个降价文件创建简单的 2 页站点?
- angular - RXJS 6:新版本的 HttpInterceptor
- asp.net - 使用 textchanged 回发后保持 Tab 索引
- html - 将页面中的元素列表居中
- javascript - Vue.js 将方法从父级传递给子级
- forms - MS Access - 报告到 PDF - 数据字段未填充在 PDF 的控件中
- python-3.x - 如何在 Py3 中检索 argv ORIGINAL 字节数据?
- linux - Unix - 将 IP 字段更改为 csv 并输出新文件
- php - PHP 查询 - 进入流程