std::fstream 的惊人结果
Surprising results with std::fstream
我编写了一个简短的程序来生成间隔均匀的随机数字并将它们保存到通用文本文件中。如果我要求它生成恰好 786432 位数字(每六位空格),输出将显示为随机的中文和日文字符。为什么?
我将标准库 类 用于文件 I/O 并使用 64 位 Xorshift 作为我的 PRNG。
程序(在MSVC下编译):
#include <iostream>
#include <fstream>
#include <algorithm>
// From https://en.wikipedia.org/wiki/Xorshift
uint64_t xorsh64star(uint64_t* state)
{
uint64_t x = *state;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
state[0] = x;
return x * 0x2545F4914F6CDD1D;
}
int main()
{
uint64_t nDigits = 0;
uint64_t wordLen = 1;
std::cout << "How many digits?\n";
std::cin >> nDigits;
std::cout << "How many digits/word?\n";
std::cin >> wordLen;
std::fstream* txt = new std::fstream("randTxt.txt", std::ios::out);
std::cout << "writing...";
uint64_t charCtr = 0;
uint64_t xorshState = 1103515245U; // GLIB C init constant, from https://www.shadertoy.com/view/XlXcW4
for (uint64_t i = 0; i < nDigits; i += 1)
{
uint64_t rnd = xorsh64star(&xorshState) % uint64_t(9);
*txt << rnd;
charCtr += 1;
if (!(charCtr % wordLen) && charCtr != 1)
{
*txt << ' ';
charCtr += 1;
}
}
std::cout << "finished! :D";
return 0;
}
输出786431个数字:
输出786432位:
输出786433个数字:
下面的答案很有帮助,但实际上并没有更正所报告的问题。该问题仅在 Windows notepad.exe 编辑器中出现。它在一个非常具体的实例中错误地显示了文件。无论如何,我希望有人能找到有用的答案。
使用 new
创建文件流看起来很不寻常,在此代码中没有必要。这样做还意味着您需要使用 delete
来正确刷新、关闭和销毁流对象。
替换为:
std::fstream* txt = new std::fstream("randTxt.txt", std::ios::out);
与:
std::fstream txt("randTxt.txt", std::ios::out);
你的写作看起来像:
txt << rnd;
当流对象超出范围时,它会很好地关闭文件并释放它持有的所有资源。
这里是修复。我不确定是什么导致了原始问题,但是一旦 if
语句更改为:
if (!(charCtr % wordLen) && charCtr != 1
{
txt << ' ';
// charCtr += 1; // This makes each word after the first 1 digit shorter.
}
最终的 .txt 文件现在可以正确显示,这解决了您的记事本查看问题并且您的所有单词现在都有 6 位数字,而不仅仅是第一个。
最初,我通过在 Win 10 64 位上使用 MSVS17 编译您的代码重现了同样的问题:
我编写了一个简短的程序来生成间隔均匀的随机数字并将它们保存到通用文本文件中。如果我要求它生成恰好 786432 位数字(每六位空格),输出将显示为随机的中文和日文字符。为什么? 我将标准库 类 用于文件 I/O 并使用 64 位 Xorshift 作为我的 PRNG。
程序(在MSVC下编译):
#include <iostream>
#include <fstream>
#include <algorithm>
// From https://en.wikipedia.org/wiki/Xorshift
uint64_t xorsh64star(uint64_t* state)
{
uint64_t x = *state;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
state[0] = x;
return x * 0x2545F4914F6CDD1D;
}
int main()
{
uint64_t nDigits = 0;
uint64_t wordLen = 1;
std::cout << "How many digits?\n";
std::cin >> nDigits;
std::cout << "How many digits/word?\n";
std::cin >> wordLen;
std::fstream* txt = new std::fstream("randTxt.txt", std::ios::out);
std::cout << "writing...";
uint64_t charCtr = 0;
uint64_t xorshState = 1103515245U; // GLIB C init constant, from https://www.shadertoy.com/view/XlXcW4
for (uint64_t i = 0; i < nDigits; i += 1)
{
uint64_t rnd = xorsh64star(&xorshState) % uint64_t(9);
*txt << rnd;
charCtr += 1;
if (!(charCtr % wordLen) && charCtr != 1)
{
*txt << ' ';
charCtr += 1;
}
}
std::cout << "finished! :D";
return 0;
}
输出786431个数字:
输出786432位:
输出786433个数字:
下面的答案很有帮助,但实际上并没有更正所报告的问题。该问题仅在 Windows notepad.exe 编辑器中出现。它在一个非常具体的实例中错误地显示了文件。无论如何,我希望有人能找到有用的答案。
使用 new
创建文件流看起来很不寻常,在此代码中没有必要。这样做还意味着您需要使用 delete
来正确刷新、关闭和销毁流对象。
替换为:
std::fstream* txt = new std::fstream("randTxt.txt", std::ios::out);
与:
std::fstream txt("randTxt.txt", std::ios::out);
你的写作看起来像:
txt << rnd;
当流对象超出范围时,它会很好地关闭文件并释放它持有的所有资源。
这里是修复。我不确定是什么导致了原始问题,但是一旦 if
语句更改为:
if (!(charCtr % wordLen) && charCtr != 1
{
txt << ' ';
// charCtr += 1; // This makes each word after the first 1 digit shorter.
}
最终的 .txt 文件现在可以正确显示,这解决了您的记事本查看问题并且您的所有单词现在都有 6 位数字,而不仅仅是第一个。
最初,我通过在 Win 10 64 位上使用 MSVS17 编译您的代码重现了同样的问题: