Как читать данные из файла из функции - PullRequest
0 голосов
/ 15 мая 2018

Я хочу сделать мой код более эффективным, особенно чтение данных из текстового файла. Вот снимок того, как это выглядит сейчас:

values V(name); 
    V.population = read_value(find_line_number(name, find_in_map(pop, mapping)));
    V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)));
... // and so on

По сути, функция read_value создает объект ifstream, открывает файл, читает одну строку данных и закрывает соединение с файлом. Это случается много раз. Что я хочу сделать, это открыть файл один раз, прочитать каждую строку, которая необходима в структуре, а затем закрыть соединение с файлом.

Вот создающая * struct структура values с параметрами:

static values create_struct(std::string name, std::map<std::string, int> mapping) {
    values V(name); 
    V.population = read_value(find_line_number(name, find_in_map(pop, mapping)), file);
    V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)), file);
    // more values here
    return V;
}

Функция, которая вызывает create_struct, показана ниже:

void initialize_data(string name) {
    // read the appropriate data from file into a struct
    value_container = Utility::create_struct(name, this->mapping);
}

Я имею в виду вместо определения объекта ifstream в функции initialize_data. Учитывая, что показано в моей программе, будет ли это лучшим местом для создания объекта файла, открытия соединения, считывания значений, а затем закрытия соединения? Кроме того, мне нужно было бы передать объект ifstream в структуру create_values, и если да, по значению, ссылке или указателю?

1 Ответ

0 голосов
/ 15 мая 2018

Краткий ответ - сначала создать свой объект ifstream и передать его как ссылку на ваш синтаксический анализатор. Не забудьте искать поток обратно в начало, прежде чем покинуть свою функцию или когда вы начнете читать.

RAII должен создать объект-оболочку, который автоматически делает это, когда выходит из области видимости.

class ifStreamRef{
    ifStreamRef(std::ifstream& _in) : mStream(_in){}
    ~ifStreamRef(){mStream.seekg(0);}
    std::ifstream& mStream;
}

Затем вы создаете экземпляр оболочки при вводе метода, который будет читать fstream.

void read_value(std::ifstream& input, ...){
    ifStreamRef autoRewind(input);
}

Или, поскольку Ctor может выполнять преобразование ...

void read_value(ifStreamRef streamRef, ...) {
    streamRef.mStream.getLine(...);
}

std :: ifstream сам следует RAII, поэтому он закроет () поток для вас, когда ваш поток выйдет из области видимости.


Длинный ответ заключается в том, что вы должны прочитать о внедрении зависимости. Не создавайте зависимости внутри объектов / функций, которые могут быть общими. Есть много видео и документов по внедрению и инверсии зависимостей.

По сути, создайте объекты, от которых зависят ваши объекты, и передайте их в качестве параметров.

Внедрение теперь зависит от интерфейса объектов, которые вы передаете. Поэтому, если вы измените свой класс ifStreamRef, чтобы он действовал как интерфейс:

class ifStreamRef{
    ifStreamRef(std::ifstream& _in) : mStream(_in){}
    ~ifStreamRef(){mStream.seekg(0);}

    std::string getLine(){
        // todo : mStream.getLine() + return "" on error;
    } 
    bool eof() { return mStream.eof(); }
    std::ifstream& mStream;
}

Затем вы можете изменить внутреннюю реализацию, которая будет принимать ссылку на vector<string>& вместо ifstream ...

class ifStreamRef{
    ifStreamRef(std::vector<string>& _in) : mStream(_in), mCursor(0){}
    ~ifStreamRef(){}

    std::string getLine(){
        // todo : mStream[mCursor++] + return "" on error;
    } 
    bool eof() { return mCursor >= mStream.size(); }
    std::vector<string>& mStream;
    size_t mCursor;
}

Я упростил несколько вещей.

...