我发现自己编写的代码看起来像这样
// Treat the following as pseudocode - just an example
iofile.seekg(0, std::ios::end); // iofile is a file opened for read/write
uint64_t f_len = iofile.tellg();
if(f_len >= some_min_length)
{
// Focus on the following code here
char *buf = new char[7];
char buf2[]{"MYFILET"}; // just some random string
// if we see this it's a good indication
// the rest of the file will be in the
// expected format (unlikely to see this
// sequence in a "random file", but don't
// worry too much about this)
iofile.read(buf, 7);
if(memcmp(buf, buf2, 7) == 0) // I am confident this works
{
// carry on processing file ...
// ...
// ...
}
}
else
cout << "invalid file format" << endl;
这段代码可能是打开文件时我们可能想要做的一个好的草图,该文件有一些指定的格式(我已经指定了)。我们做了一些初步检查,以确保字符串"MYFILET"
位于文件的开头 - 因为我已经确定我所做的工作的所有文件都将从这个序列开始字符。
我认为如果我们不必使用&#34; c-style&#34;那么这段代码会更好。字符数组,但在任何地方都使用字符串。 这将是有利的,因为我们可以执行if(buf == buf2)
buf
和buf2
std::string
s。
可能的替代方案是,
// Focus on the following code here
std::string buf;
std::string buf2("MYFILET"); // very nice
buf.resize(7); // okay, but not great
iofile.read(buf.data(), 7); // pretty awful - error prone if wrong length argument given
// also we have to resize buf to 7 in the previous step
// lots of potential for mistakes here,
// and the length was used twice which is never good
if(buf == buf2) then do something
这有什么问题?
7
(或在这种情况下为常量)两次。这是介于&#34;不理想&#34;并且&#34;可能容易出错&#34;。buf
访问.data()
的内容,我假设这里实现了返回某种原始指针。 我个人不太介意,但其他人可能更喜欢更安全的内存解决方案,也许暗示我们应该使用某种迭代器?我认为在Visual Studio中(对于Windows用户我不是),这可能会返回一个迭代器,这会给出[?]警告/错误[?] - 对此不确定。buf
添加额外的调整大小声明。如果buf
的大小可以以某种方式自动设置,那会更好。答案 0 :(得分:2)
写入const char*
返回的std::string::data()
是未定义的行为。但是,您可以这种方式自由使用std::vector::data()
。
如果你想使用std :: string,并且不喜欢自己设置大小,你可以考虑是否可以使用std::getline()
。这是免费功能,而不是std::istream::getline()
。 std::string
版本将读取到指定的分隔符,因此如果您有文本格式,则可以告诉它在'\0'
或其他一些永不发生的字符之前读取,并且它将自动调整给定的大小用于保存内容的字符串。
如果您的文件本质上是二元文件,而不是文字,我认为大多数人会发现std::vector<char>
比std::string
更自然。
答案 1 :(得分:1)
我们必须使用长度变量7(或在这种情况下为常数)两次。 这介于“不理想”和“可能容易出错”之间。
第二次使用buf.size()
iofile.read(buf.data(), buf.size());
我们必须使用.data()来访问buf的内容 假设这里实现了返回某种原始指针。
John Zwinck指出,.data()
返回指向const
的指针。
我想您可以将buf
定义为std::vector<char>
;对于vector
(如果我没错),.data()
会返回指向char
(在这种情况下)的指针,而不是const char
。
size()
和resize()
的工作方式相同。
我们必须为buf添加一个额外的resize语句。这将是 如果可以以某种方式自动设置buf的大小,那就更好了。
我认为read()
不允许这样做。
p.s:抱歉我的英语不好。
答案 2 :(得分:0)
template<class Src>
std::string read_string( Src& src, std::size_t count){
std::string buf;
buf.resize(count);
src.read(&buf.front(), 7); // in C++17 make it buf.data()
return buf;
}
现在auto read = read_string( iofile, 7 );
在使用时很干净。
buf2
是一个糟糕的计划。我做了:
if(read=="MYFILET")
直接使用,或使用const char myfile_magic[] = "MYFILET";
。
答案 3 :(得分:0)
我们可以在没有双缓冲(rdbuf和字符串)的情况下验证签名并从堆中分配...
// terminating null not included
constexpr char sig[] = { 'M', 'Y', 'F', 'I', 'L', 'E', 'T' };
auto ok = all_of(begin(sig), end(sig), [&fs](char c) { return fs.get() == (int)c; });
if (ok) {}
答案 4 :(得分:0)
我喜欢上面例子中的许多想法,但我并不完全满意,有一个答案可以为C ++ 11和C ++生成不定义的行为代码17。我目前在C ++ 11中编写了大部分代码 - 因为我不希望将来在的机器上使用它,它没有C ++ 11编译器。
如果没有,那么我添加一个新的编译器或更改机器。
然而,在我看来,编写一些我知道可能无法在C ++下工作的代码确实是个坏主意......这只是我个人的意见。我不希望再次使用此代码,但我不希望将来为自己制造潜在的问题。
因此我提出了以下代码。 我希望其他用户会提供反馈以帮助改善这一点。(例如,目前还没有错误检查。)
std::string
fstream_read_string(std::fstream& src, std::size_t n)
{
char *const buffer = new char[n + 1];
src.read(buffer, n);
buffer[n] = '\0';
std::string ret(buffer);
delete [] buffer;
return ret;
}
这似乎是一个基本的,可能是万无一失的方法......很遗憾,似乎没有办法让std :: string使用与{{1}调用分配的内存相同的内存}。
注意我们必须在C风格的字符串中添加一个额外的尾随空字符,该字符在C ++风格的new
中被切掉。