Я пытался прочитать файл в 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;
,
Предполагая, что вы можете сойти с рук, просто игнорируя 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
в структуру их собственного. Хотя это только предположение, я думаю, что вы наверное хочу сделать это в любом случае.
В обмен на некоторую дополнительную длину вы получаете безопасность типов, и если у вас есть несколько различных частей кода, которые должны читать подобные записи, это намного больше удобства.
Вопреки утверждению Бена Фойгта, фактическое тестирование показывает, что ввод-вывод с использованием iostreams может полностью конкурировать с функциями stdio C (и в некоторых случаях быстрее). Я не достаточно тестировал этот конкретный случай, чтобы убедиться, что он быстрее, медленнее или примерно таким же, но я провел достаточно другое тестирование, чтобы с достаточной уверенностью сказать, что далеко не предрешено, что функции C stdio будут существенно Быстрее.
Итог: вполне возможно, что продолжать использовать scanf
это хороший выбор — но опять же, это может и не быть.
Просто используйте оригинальный код. Лучше в каждый путь:
Тем не менее, я предложу одно улучшение:
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 была та же ошибка, в дополнение к проблеме, связанной с промежуточным текстом.
Примечание: вы никогда не заметите разницу в скорости для пользовательского ввода или даже для вывода на терминал. Но для файлового ввода-вывода (включая перенаправленный stdin или stdout) функции stdio.h значительно превосходят iostreams.