读取二进制文件的惯用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.
此外,特别是对于前C 17,您可以使用std :: vector< unsigned char>或者std :: vector< char>如果你没有或想要使用std :: byte.
标签:c,file,io,c17 来源: https://codeday.me/bug/20191007/1865085.html