Я пытался прочитать файл в 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 = " >> я >> "; j = " >> j >> "; a = " >> a >> "; b = " >> b >> ";\n";
Любая помощь будет оценена. Благодарю!
Редактировать: проблема, с которой я столкнулся, заключается в том, что строка с пернументом не отформатирована правильно. Поскольку мой файл находится в форме, указанной в вопросе, я не могу написать inputfile >> я >> 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 может быть полностью конкурентным с функциями C stdio (и быстрее в некоторых случаях). Я не тестировал этот конкретный случай, чтобы убедиться, что он быстрее, медленнее или примерно то же самое, но я сделал достаточно другого тестирования, чтобы с достаточной уверенностью сказать, что он далеко не предрешен, что функции 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 имел ту же ошибку, в дополнение к проблеме, связанной с промежуточным текстом.
Nota Bene: Вы никогда не заметите разницу в скорости для ввода пользователем или даже для вывода на терминал. Но для файлового ввода-вывода (включая перенаправленный stdin или stdout), функции stdio.h сильно били iostreams.
i =
,j =
и т. Д., Или все в порядке, просто игнорировать их и читать числа?