C ++, как написать ifstream для нескольких файлов? - PullRequest
0 голосов
/ 27 марта 2019

Итак, у меня есть несколько файлов, которые формируют условное число строк, поэтому давайте назовем их file1, file2, file3 и так далее.Я хочу создать класс istream, который передает все файлы так, как если бы они были одним целым.Одна вещь, которую я получил, это не подкласс std :: istream, а переопределение streambuf.Мой вопрос: как бы я поступил по этому поводу - как бы я мог читать из нескольких файлов, не имея их всех в памяти?

1 Ответ

1 голос
/ 27 марта 2019

Можно ли сделать istream, который читает несколько файлов?

Да, но вам придется сделать это самостоятельно. Вы можете реализовать свой собственный класс istream, расширив std::istream, а затем реализовав методы, которые он определяет:

class custom_istream : public std::istream {
    std::ifstream underlying; 
    //... implement methods
};

Интерфейс std::istream достаточно гибок, чтобы позволить вам делать то, что вы хотите. Однако , реализация std::istream потребует много работы, так как вам придется реализовать весь интерфейс.

Есть ли более простое решение?

Если вам нужен только набор функций, предоставляемых std::istream, вы можете просто написать свой собственный класс.

Например, если вам нужно только прочитать строки из файла, приведенный ниже класс будет отлично работать для нескольких файлов:

class MultiFileReader {
    std::ifstream filestream; 
    std::ios_base::openmode mode;  
    size_t file_index = 0; 
    std::vector<std::string> filenames; 
    void open_next_file() {
        file_index++; 
        filestream = std::ifstream(filenames.at(file_index), mode); 
    }
   public:
    MultiFileReader(std::vector<std::string> const& files, std::ios_base::openmode mode)
      : filestream(files[0], mode), mode(mode) {}
    // Checks if there's no more files to open, and no more to read
    // in the current file
    bool hasMoreToRead() {
        if(file_index == filenames.size()) return false;
        if(file_index + 1 == filenames.size()) 
            return not filestream.eof(); 
        return true;
    }
    std::string read_line() {
        if(not hasMoreToRead()) {
            throw std::logic_error("No more to read"); 
        }
        // If at the end of the file, open the next file
        if(filestream.eof()) {
            open_next_file(); 
        }
        else {
            std::string line; 
            std::getline(filestream, line);
            return line; 
        }
    }
};  
...