[英]Off-by-one errors when reading a file one chunk at a time
由於實現定義的問題, 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);
}
}
這適用於二進制文件(我有一個單獨的 function ),但對於我需要保留換行符的字符串版本,如果塊包含換行符,則會產生一個錯誤。 這會導致塊中的最后一個字符被復制為下一個字符中的第一個字符:
預期 output
difficulty=Normal
controlpref=Mouse
sound=5
music=5
cameraShakeStrength=1.000000
實際 output
difficulty=Normal
coontrolpref=Mouse
souund=5
musiic=5
camerraShakeStrength=1.000000
使用格式化的ifstream::get
默認使用換行符作為分隔符並完全跳過它(同樣,需要保留換行符)並導致交錯的 output 和丟棄的字符:
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.