Чтение из файла: C на C ++

0

Я пытался прочитать файл в 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; ,

  • 0
    так с какой проблемой вы сталкиваетесь?
  • 0
    Вам действительно нужно проверить наличие i = , j = и т. Д., Или все в порядке, просто игнорировать их и читать числа?
Показать ещё 5 комментариев
Теги:
io
input
inputstream

2 ответа

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 в свою собственную структуру. Хотя это всего лишь предположение, я предполагаю, что вы, вероятно, захотите это сделать в любом случае.

В обмен на некоторую дополнительную длину вы получаете безопасность типов, и если у вас есть несколько разных частей вашего кода, которые должны читать записи, подобные этому, гораздо удобнее.

Вопреки утверждению Бена Войгта, фактическое тестирование показывает, что ввод-вывод с использованием iostreams может быть полностью конкурентным с функциями C stdio (и быстрее в некоторых случаях). Я не тестировал этот конкретный случай, чтобы убедиться, что он быстрее, медленнее или примерно то же самое, но я сделал достаточно другого тестирования, чтобы с достаточной уверенностью сказать, что он далеко не предрешен, что функции C stdio будут существенно Быстрее.

Итог: возможно, что продолжение использования scanf - хороший выбор, но опять же, возможно, это и не так.

3

Просто используйте оригинальный код. Это лучше во всех отношениях:

  • Он работает (кроме случаев, когда файл заканчивается пустой строкой, см. Ниже).
  • Он протестирован.
  • Он работает быстрее.
  • Он отлично подходит как для C, так и для C++.
  • Он компилируется быстрее.

Однако я предложу одно улучшение:

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.

  • 0
    Я просто собирался упомянуть вещь eof / feof. Хороший звонок.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню