c++ - 一次读取一个文件时出现一个错误
问题描述
ifstream::readsome
由于实现定义的问题,它对于读取文件块是出了名的糟糕。就我而言,MSVC 在新打开的文件上返回 0。
我查看了他们的实现并意识到他们只是ifstream::read
在后台调用:
MSVC 实施
streamsize __CLR_OR_THIS_CALL readsome(_Elem* _Str,
streamsize _Count) { // read up to _Count characters into buffer, without blocking
ios_base::iostate _State = ios_base::goodbit;
_Chcount = 0;
const sentry _Ok(*this, true);
streamsize _Num;
if (!_Ok) {
_State |= ios_base::failbit; // no buffer, fail
} else if ((_Num = _Myios::rdbuf()->in_avail()) < 0) {
_State |= ios_base::eofbit; // no characters available
} else if (0 < _Count && 0 < _Num) { // read available
read(_Str, _Num < _Count ? _Num : _Count);
}
_Myios::setstate(_State);
return gcount();
}
所以我实现了我自己的,只是调用ifstream::read
:
我的实现
std::optional<std::string> ReadSomeStringFromFile(std::ifstream& ifs, std::streampos pos, std::streamsize count) noexcept {
if(ifs && ifs.is_open()) {
auto result = std::string(count, '\0');
ifs.seekg(pos);
ifs.read(result.data(), count);
if(ifs.gcount()) {
return result;
}
}
return {};
}
用法:
std::streampos pos{0};
std::streamsize count{10};
std::ifstream ifs{g_options_filepath};
{
auto stream = FileUtils::ReadSomeStringFromFile(ifs, pos, count);
while(stream.has_value()) {
DebuggerPrintf(stream.value().c_str());
pos += count;
stream = FileUtils::ReadSomeStringFromFile(ifs, pos, count);
}
}
这适用于二进制文件(我有一个单独的函数),但对于需要保留换行符的字符串版本,如果块包含换行符,则会产生一个错误。这会导致块中的最后一个字符被复制为下一个字符中的第一个字符:
预期产出
difficulty=Normal
controlpref=Mouse
sound=5
music=5
cameraShakeStrength=1.000000
实际输出
difficulty=Normal
coontrolpref=Mouse
souund=5
musiic=5
camerraShakeStrength=1.000000
默认情况下使用 formattedifstream::get
使用换行符作为分隔符并完全跳过它(同样,需要保留换行符)并导致交错输出和丢弃字符:
difficult=Normalontrolpre=Mouseund=5ic=5raShakeStength=1.00000
问题
有没有办法尝试在格式化数据上使用未格式化的输入函数,或者我不应该尝试使用文本数据?
解决方案
我不get
经常使用,所以我忘记了它的存在。使用这个答案作为指导,我想出了一个解决方案:
(我仔细检查过,使用FormattedInput
as的另一个答案(ifs >> std::noskipws >> ch)
给出了相同的结果,即使get
规范说它把它当作UnformattedInput
)
[[nodiscard]] std::optional<std::string> ReadSomeStringBufferFromFile(std::ifstream& ifs, std::streampos pos, std::streamsize count /*= 0u*/) noexcept {
if(!(ifs && ifs.is_open())) {
return {};
}
ifs.seekg(pos, std::ios::beg);
//Would like to early-out here,
//but MSVC ifstream::seekg doesn't set the fail bit,
//so can't early-out until the get call.
char ch{};
std::string result{};
result.reserve(count);
bool readsome{false}; //If nothing read, make std::optional::has_value false.
while(ifs && ifs.get(ch) && count > 0) {
result.append(1, ch);
--count;
readsome |= true;
}
return readsome ? std::make_optional(result) : std::nullopt;
推荐阅读
- svelte - 如何通过第三方 Svelte 组件转发事件?
- javascript - Reactjs 在地图函数中按摩来自两个不同道具字段的数据
- postgresql - 使用 scalikejdbc 插入默认值
- equality - 寻找包含列表可判定相等性的 Agda 模块
- perl - 如何在单个 perl regx 中同时执行负前瞻和负后瞻?
- amazon-web-services - terraform 给出错误模块参数的值无效
- docker - MySQL与本机数据库的连接错误
- c# - 在 .Where 子句中使用的链接谓词
- prometheus - 如何计算“锯”:来自源计数器的每日计数器
- azure - Azure 中国:不支持更改跟踪