rdbuf() 奇怪的行为
rdbuf() strange behavior
我试图通过简单地使用 rdbuf() 将两个文件合并为一个文件,但是在合并时,文件的第一行丢失了。代码如下:
void mergeFiles(ifstream &file1, ifstream &file2, ofstream &file3) {
int num1;
int num2;
string firstLine_1;
string firstLine_2;
getline(file1, firstLine_1);
num1 = atoi(firstLine_1.c_str());
getline(file2, firstLine_2);
num2 = atoi(firstLine_2.c_str());
if (num1<num2) {
file3 << file1.rdbuf() << "\n" << file2.rdbuf();
} else {
file3 << file2.rdbuf() << "\n" << file1.rdbuf();
}
}
file3 << filen.rdbuf()
从 filen
流中的当前位置向前复制到 file3
。当前位置在第一行之后,因为您刚刚阅读它。
找回开头,你漏掉的那一行就不会再漏掉了。
好吧,您在连接其余文件之前先拉出每个文件的第一行,这是预期的。不过,您仍然有这些行,所以只需在它们之间打印它们:
if (num1<num2) {
file3 << firstLine_1 << "\n"
<< file1.rdbuf() << "\n"
<< firstLine_2 << "\n"
<< file2.rdbuf();
} else {
file3 << firstLine_2 << "\n"
<< file2.rdbuf() << "\n"
<< firstLine_1 << "\n"
<< file1.rdbuf();
}
附录: @BenVoigt 正确地指出,如果其中一个文件包含不以换行符结尾的单行,则其输出将不同于打印普通文件文件内容由一个换行符分隔(中间或末尾会有一个额外的换行符)。
由于第一个 getline
调用会设置文件结束标志,因此这种情况是可识别的,可以通过以下方式避免这种情况:
if (num1<num2) {
file3 << firstLine_1;
if(file1) { file3 << "\n" << file1.rdbuf(); }
file3 << "\n";
file3 << firstLine_2;
if(file2) { file3 << "\n" << file2.rdbuf(); }
} else {
file3 << firstLine_2;
if(file2) { file3 << "\n" << file2.rdbuf(); }
file3 << "\n";
file3 << firstLine_1;
if(file1) { file3 << "\n" << file1.rdbuf(); }
}
由于这是冗长且重复的内容,我会考虑使用 lambda 使其更简洁:
auto printfile = [&file3](std::string const &firstline, std::istream &in) {
file3 << firstline;
if(in) { file3 << "\n" << in.rdbuf(); }
};
if(num1 < num2) {
printfile(firstLine_1, file1);
file3 << "\n";
printfile(firstLine_2, file2);
} else {
printfile(firstLine_2, file2);
file3 << "\n";
printfile(firstLine_1, file1);
}
对于像这样的常规文件,回溯也是一种可能,但我觉得最好避免在没有令人信服的理由的情况下放弃在管道、套接字和其他不可寻找的流上使用代码的能力,即使这似乎是一个不太可能的用例。
我试图通过简单地使用 rdbuf() 将两个文件合并为一个文件,但是在合并时,文件的第一行丢失了。代码如下:
void mergeFiles(ifstream &file1, ifstream &file2, ofstream &file3) {
int num1;
int num2;
string firstLine_1;
string firstLine_2;
getline(file1, firstLine_1);
num1 = atoi(firstLine_1.c_str());
getline(file2, firstLine_2);
num2 = atoi(firstLine_2.c_str());
if (num1<num2) {
file3 << file1.rdbuf() << "\n" << file2.rdbuf();
} else {
file3 << file2.rdbuf() << "\n" << file1.rdbuf();
}
}
file3 << filen.rdbuf()
从 filen
流中的当前位置向前复制到 file3
。当前位置在第一行之后,因为您刚刚阅读它。
找回开头,你漏掉的那一行就不会再漏掉了。
好吧,您在连接其余文件之前先拉出每个文件的第一行,这是预期的。不过,您仍然有这些行,所以只需在它们之间打印它们:
if (num1<num2) {
file3 << firstLine_1 << "\n"
<< file1.rdbuf() << "\n"
<< firstLine_2 << "\n"
<< file2.rdbuf();
} else {
file3 << firstLine_2 << "\n"
<< file2.rdbuf() << "\n"
<< firstLine_1 << "\n"
<< file1.rdbuf();
}
附录: @BenVoigt 正确地指出,如果其中一个文件包含不以换行符结尾的单行,则其输出将不同于打印普通文件文件内容由一个换行符分隔(中间或末尾会有一个额外的换行符)。
由于第一个 getline
调用会设置文件结束标志,因此这种情况是可识别的,可以通过以下方式避免这种情况:
if (num1<num2) {
file3 << firstLine_1;
if(file1) { file3 << "\n" << file1.rdbuf(); }
file3 << "\n";
file3 << firstLine_2;
if(file2) { file3 << "\n" << file2.rdbuf(); }
} else {
file3 << firstLine_2;
if(file2) { file3 << "\n" << file2.rdbuf(); }
file3 << "\n";
file3 << firstLine_1;
if(file1) { file3 << "\n" << file1.rdbuf(); }
}
由于这是冗长且重复的内容,我会考虑使用 lambda 使其更简洁:
auto printfile = [&file3](std::string const &firstline, std::istream &in) {
file3 << firstline;
if(in) { file3 << "\n" << in.rdbuf(); }
};
if(num1 < num2) {
printfile(firstLine_1, file1);
file3 << "\n";
printfile(firstLine_2, file2);
} else {
printfile(firstLine_2, file2);
file3 << "\n";
printfile(firstLine_1, file1);
}
对于像这样的常规文件,回溯也是一种可能,但我觉得最好避免在没有令人信服的理由的情况下放弃在管道、套接字和其他不可寻找的流上使用代码的能力,即使这似乎是一个不太可能的用例。