Добавление метода в существующий класс для чтения содержимого файла строка за строкой - PullRequest
0 голосов
/ 07 июня 2019

Я знаю, что было задано много подобных вопросов, таких как:

Однако у меня уже есть класс с определенным поведением, которое я не хочу нарушать и что бы я хотелсделать, это добавить дополнительную функцию к этому классу.

Текущий класс, над которым я работаю, является базовым TextFileReader классом, и он наследуется от FileHandler класса.Я покажу текущую иерархию классов, чтобы вы могли видеть то, что у меня уже есть: вы можете игнорировать ExceptionHandler, который используется, поскольку он не имеет отношения к этому вопросу, но я оставил его здесь, так как именно так определяется мой класс.


FileHandler.h

#pragma once

#include <string>
#include <sstream>
#include <fstream>

namespace util {

    class FileHandler {
    protected:
        std::fstream    fileStream_;
        std::string     filePath_;
        std::string     filenameWithPath_;

    private:
        bool saveExceptionInLog_;

    public:
        virtual ~FileHandler();

        FileHandler(const FileHandler& c) = delete;
        FileHandler& operator=(const FileHandler& c) = delete;

    protected:
        FileHandler(const std::string& filename, bool saveExceptionInLog);

        void throwError(const std::string& message) const;
        void throwError(const std::ostringstream& streamMessage) const;
    };

} // namespace util

FileHandler.cpp

#include "FileHandler.h"
#include "ExceptionHandler.h"

using namespace util;

FileHandler::FileHandler(const std::string & filename, bool saveExceptionInLog) :
    saveExceptionInLog_(saveExceptionInLog),
    filenameWithPath_(filename) {
    // Extract path info if it exists
    std::string::size_type lastIndex = filename.find_last_of("/\\");
    if (lastIndex != std::string::npos) {
        filePath_ = filename.substr(0, lastIndex);
    }

    if (filename.empty()) {
        throw ExceptionHandler(__FUNCTION__ + std::string(" missing filename", saveExceptionInLog_));

    }
}

FileHandler::~FileHandler() {
    if (fileStream_.is_open()) {
        fileStream_.close();
    }
}

void FileHandler::throwError(const std::string & message) const {
    throw ExceptionHandler("File [" + filenameWithPath_ + "] " + message, saveExceptionInLog_);
}

void FileHandler::throwError(const std::ostringstream & streamMessage) const {
    throwError(streamMessage.str());
}

TextFileReader.ч

#pragma once

#include "FileHandler.h"

namespace util {

    class TextFileReader : public FileHandler {
    public:
        explicit TextFileReader(const std::string& filename);
        virtual ~TextFileReader() = default;

        TextFileReader(const TextFileReader& c) = delete;
        TextFileReader& operator=(const TextFileReader& c) = delete;

        std::string readAll() const;    

    };

} // namespace util

TextFileReader.cpp

#include "TextFileReader.h"

using namespace util;

TextFileReader::TextFileReader(const std::string & filename) :
FileHandler( filename, true ) {
    fileStream_.open(filenameWithPath_.c_str(), std::ios_base::in);
    if (!fileStream_.is_open()) {
        throwError(__FUNCTION__ + std::string(" can not open file for reading"));
    }
}

std::string TextFileReader::readAll() const { 
    std::ostringstream stream;
    stream << fileStream_.rdbuf();

    return stream.str();
}

Что я хотел бы сделать или что я пытаюсь сделать, этодобавьте этот метод к моим TextFileReader

std::vector<std::string> readLineByLine() const;

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

Некоторые изПроблемы, с которыми я столкнулся, заключаются в том, что в базовом классе я храню объект fstream, а не объект ifstream или ofstream, поэтому попытка использовать std::getline в цикле не работает.Я пытался читать построчно прямо из дескриптора файлового потока.

При следующей попытке я попытался повторно использовать уже существующий readAll(), прочитать все содержимое файла в одном буфере и вернуть его обратно как одну строку, а затем проанализировать эту строку в вектор строк.При таком подходе в цикле while я все еще не могу использовать std::getline, потому что он использует объект ostringstream, а не объект istringstream.


Функция должна работать примерно так - псевдокод:

std::vector<std::string> TextFileReader::readLineByLine() const {
    // get contents from file either line by line and store
    // each line into a string and push that string into a
    // vector of strings then return that vector after all 
    // lines have been read.

   // or...

   // read all contents from file into single string buffer and parse
   // that string into a vector of strings and return that vector.
}

И вот тут у меня проблема.Любые предложения?

Редактировать

Я изначально пробовал пользовательский подход Bapo's, но я получал эту ошибку компилятора:

1>------ Build started: Project: ChemLab, Configuration: Debug Win32 ------
1>TextFileReader.cpp
1>c:\...\textfilereader.cpp(24): error C2665: 'std::getline': none of the 2 overloads could convert all the argument types
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\string(160): note: could be 'std::basic_istream<char,std::char_traits<char>> &std::getline<char,std::char_traits<char>,std::allocator<char>>(std::basic_istream<char,std::char_traits<char>> &,std::basic_string<char,std::char_traits<char>,std::allocator<char>> &)'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\string(129): note: or       'std::basic_istream<char,std::char_traits<char>> &std::getline<char,std::char_traits<char>,std::allocator<char>>(std::basic_istream<char,std::char_traits<char>> &&,std::basic_string<char,std::char_traits<char>,std::allocator<char>> &)'
1>c:\...\textfilereader.cpp(24): note: while trying to match the argument list '(const std::fstream, std::string)'
1>Done building project "ChemLab.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Однако пользователькто-то заметил, что если я сделаю fileStream_ изменяемым, функция const не будет работать.Я пошел дальше и добавил изменяемый модификатор к члену fileStream_, и теперь функция компилируется.

1 Ответ

2 голосов
/ 07 июня 2019

Вы можете сделать что-то столь же простое, как это:

std::vector<std::string> TextFileReader::readLineByLine() {
    std::vector<std::string> return_vector{};
    std::string line;
    while(std::getline(fileStream_, line)) {
        return_vector.push_back(line);
    }
    return return_vector;

}

Хотя после этого весь ваш поток будет прочитан и будет "пустым"

РЕДАКТИРОВАТЬ: забыл на самом делевернуть вектор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...