我一直在尝试阅读C/C++
中的文件并且C
能够这样做,但我遇到了C++
的一些问题。
背景:我正在尝试阅读的文件具有以下结构
i = %3d; j = %3d; a = %3d; b = %3d;
i = %3d; j = %3d; a = %3d; b = %3d;
...
我在C
中使用的代码如下:
#include <stdio.h>
#include <fstream>
#define MAXSIZE 32
int main()
{
FILE* inputfile = fopen("temp.txt","r");
int i,j,a,b;
while (!feof(inputfile))
{
fscanf(inputfile,
"i = %3d; "
"j = %3d; "
"a = %3d; "
"b = %3d;\n",
&i, &j, &a, &b);
printf("%3d %3d %3d %3d\n", i,j,a,b);
}
fclose(inputfile);
return 0;
}
尝试在C++
中编写此程序时,我尝试过:
int main()
{
ifstream inputfile( "temp.txt" ,ios::in);
int i,j,a,b;
while (!std::cin.eof())
{
inputfile >> "i = " >> i >> "; j = " >> j >> "; a = " >> a >> "; b = " >> b >> ";\n";
printf("%3d %3d %3d %3d\n", i,j,a,b);
}
return 0;
}
但我不太清楚如何格式化
inputfile >> "i = " >> i >> "; j = " >> j >> "; a = " >> a >> "; b = " >> b >> ";\n";
任何帮助将不胜感激。谢谢!
编辑:我面临的问题是,最后一行没有以正确的方式格式化。因为我的文件采用问题中所述的形式,所以我不能写inputfile >> i >> j >> a >> b;
。
答案 0 :(得分:3)
只需使用原始代码即可。 每种方式都更好:
但是,我会提出一个改进:
while (4 == fscanf(inputfile,
"i = %3d; "
"j = %3d; "
"a = %3d; "
"b = %3d;\n",
&i, &j, &a, &b))
{
printf("%3d %3d %3d %3d\n", i,j,a,b);
}
if (!feof(inputfile)) {
// read failed and the reason wasn't hitting the end of the file
// maybe you've been keeping track of line numbers and
// can report where the invalid input was found
}
在尝试阅读之前测试EOF太早了。只有在读取文件结束后才会设置EOF标志。如果上次成功读取实际找到'\n'
,则不会设置EOF。除了处理插入文本的问题之外,iostreams代码也有同样的错误。
Nota Bene:您永远不会注意到用户输入的速度差异,甚至输出到终端的速度差异。但对于文件I / O(包括重定向的stdin或stdout),stdio.h函数击败了iostreams。
答案 1 :(得分:1)
假设您可以忽略i =
,j =
等等而只是需要阅读数字,那么可能会创建一个ctype方面,将这些字符分类为白色空间。使用包含该方面的区域设置对流进行标记,然后只读取您的数字:
#include <iostream>
#include <algorithm>
#include <locale>
#include <vector>
#include <sstream>
struct digits_only: std::ctype<char> {
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
return &rc[0];
}
};
class record {
int i, j, a, b;
public:
friend std::istream &operator>>(std::istream &is, record &r) {
return is >> r.i >> r.j >> r.a >> r.b;
}
friend std::ostream &operator<<(std::ostream &os, record const &r) {
return os << r.i << "\t" << r.j << "\t" << r.a << "\t" << r.b;
}
};
int main() {
std::stringstream in("i=1 j = 2 a = 10 b = 20\ni = 3 j = 4 a = 30 b = 40");
std::locale numbers(std::locale(), new digits_only);
in.imbue(numbers);
std::vector<record> records{ std::istream_iterator<record>(in),
std::istream_iterator<record>() };
std::cout << "i\tj\ta\tb\n";
for (auto const & r : records)
std::cout << r << "\n";
}
至于这是否比使用scanf
更好或更差,我会说它对某些问题持开放态度。它显然更长。 OTOH,上面代码中的很多额外长度来自于我决定将i
,j
,a
和b
包装到他们自己的结构中。虽然这只是一个猜测,我的猜测是你可能想要在任何情况下都这样做。
为了换取一些额外的长度,你可以获得类型安全性,如果你有几个不同的代码部分需要读取这样的记录,那就更方便了。
与Ben Voigt的说法相反,实际测试显示使用iostream的I / O可以与C的stdio功能完全竞争(在某些情况下更快)。我没有对这个特殊情况进行过足够的测试,以确定它是否更快,更慢,或者大致相同,但是我已经做了足够的其他测试,以合理的确定性说明C的stdio功能将会大大超出预定的结论更快。
底线:继续使用scanf
可能是一个不错的选择 - 但话说再说,它可能也不是。