我正在使用流读取C ++中的文件,特别是fstream,而不是ifstream。
blah blah blah\n
blah blah\n
blah blah blah blah \n
end
这一遍又一遍地重复
我想读取一组数据,然后将其存储在C样式结构的字符数组中。我开始尝试使用getline(),但分隔符只能是一个字符,而不是三个字符。我显然不能尝试使用read()读取一定数量的字节,因为每个集合的数字都不同。
所以我对这里最简单(最强大)的事情感到震惊。我应该调用getline直到找到'end'字符串,同时反复追加每个字符串?
我尝试了一个2D char数组但是我复制到它有点痛苦。我可以在这里使用strncpy吗?我认为这不起作用
char buf[10][10];
strncpy(buf[1], "blah blah",10);
我在这里有一些想法,但我不确定哪一个(或者我没有的那个)是最好的。
编辑: 因此,这适用于网络应用程序,因此char数组(或字符串)的大小应始终相同。此外,结构中应该没有指针。
相关问题:char数组和std :: string存储在内存中的方式是一样的吗?我总是在std :: string上有一些开销。
答案 0 :(得分:7)
嗯,你说“在C风格的结构中”,但也许你可以使用std::string
?
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
int main(void)
{
std::fstream file("main.cpp");
std::vector<std::string> lines;
std::string line;
while (getline(file, line))
{
if (line == "end")
{
break;
}
std::cout << line << std::endl;
lines.push_back(line);
}
// lines now has all the lines up-to
// and not including "end"
/* this is for reading the file
end
some stuff that'll never get printed
or addded blah blah
*/
};
答案 1 :(得分:3)
我建议使用字符串而不是字符数组。
答案 2 :(得分:2)
(我在底部描述的push_back
实用程序。)
typedef std::vector<std::string> Block;
int main() {
using namespace std;
vector<Block> blocks;
string const end = "end";
// no real difference from using ifstream, btw
for (fstream file ("filename", file.in); file;) {
Block& block = push_back(blocks);
for (string line; getline(file, line);) {
if (line == end) {
break;
}
push_back(block).swap(line);
}
if (!file && block.empty()) {
// no lines read, block is a dummy not represented in the file
blocks.pop_back();
}
}
return 0;
}
示例序列化:
template<class OutIter>
void bencode_block(Block const& block, OutIter dest) {
int len = 0;
for (Block::const_iterator i = block.begin(); i != block.end(); ++i) {
len += i->size() + 1; // include newline
}
*dest++ = len;
*dest++ = ':';
for (Block::const_iterator i = block.begin(); i != block.end(); ++i) {
*dest++ = *i;
*dest++ = '\n';
}
}
我使用了简单的bencoding序列化格式。示例合适的输出迭代器,它只写入流:
struct WriteStream {
std::ostream& out;
WriteStream(std::ostream& out) : out(out) {}
WriteStream& operator++() { return *this; }
WriteStream& operator++(int) { return *this; }
WriteStream& operator*() { return *this; }
template<class T>
void operator=(T const& value) {
out << value;
}
};
使用示例:
bencode_block(block, WriteStream(std::cout));
另一个可能的输出迭代器,它写入file descriptor(例如网络套接字):
struct WriteFD {
int out;
WriteFD(int out) : out(out) {}
WriteFD& operator++() { return *this; }
WriteFD& operator++(int) { return *this; }
WriteFD& operator*() { return *this; }
template<class T>
void operator=(T const& value) {
if (write(value) == -1) {
throw std::runtime_error(strerror(errno));
}
}
//NOTE: write methods don't currently handle writing less bytes than provided
int write(char value) {
return write(out, &value, 1);
}
int write(std::string const& value) {
return write(out, value.data(), value.size());
}
int write(int value) {
char buf[20];
// handles INT_MAX up to 9999999999999999999
// handles INT_MIN down to -999999999999999999
// that's 19 and 18 nines, respectively (you did count, right? :P)
int len = sprintf(buf, "%d", value);
return write(out, buf, len);
}
};
穷人的移动语义:
template<class C>
typename C::value_type& push_back(C& container) {
container.push_back(typename C::value_type());
return container.back();
}
这样可以轻松使用移动语义来避免不必要的副本:
container.push_back(value); // copies
// becomes:
// (C is the type of container)
container.push_back(C::value_type()); // add empty
container.back().swap(value); // swap contents
答案 3 :(得分:0)
这实际上是您正在描述的解析问题。一旦你意识到问题所在,你就已经解决了这个问题。
很难让您更具体,因为您没有真正描述您需要对数据做些什么。但通常你可以做简单的解析inlne。在这种情况下,也许你想要一个识别“blah”和EOL和“end”的小程序,并告诉你它在给定的字符串位置找到了它。
然后你可以有一个识别整行的parse_line例程(期望以EOL结尾的任何数量的“blah”)。
然后你可以有一个解析例程,调用parse_line你给定的次数(10?),然后错误,如果找不到“end”。