A toolkit for working with phylogenetic data.
v0.24.0
file_input_source.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_IO_FILE_INPUT_SOURCE_H_
2 #define GENESIS_UTILS_IO_FILE_INPUT_SOURCE_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2020 Lucas Czech and HITS gGmbH
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@h-its.org>
23  Exelixis Lab, Heidelberg Institute for Theoretical Studies
24  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
25 */
26 
36 
37 #include <cstdio>
38 #include <cerrno>
39 #include <cstring>
40 #include <istream>
41 #include <stdexcept>
42 #include <string>
43 
44 namespace genesis {
45 namespace utils {
46 
47 // =================================================================================================
48 // File Input Source
49 // =================================================================================================
50 
59 class FileInputSource final : public BaseInputSource
60 {
61 public:
62 
63  // -------------------------------------------------------------
64  // Constructors and Rule of Five
65  // -------------------------------------------------------------
66 
70  explicit FileInputSource( std::string const& file_name )
71  : file_name_( file_name )
72  {
73  if( ! file_exists( file_name ) ) {
74  throw std::runtime_error( "File does not exist or is not readable: " + file_name );
75  }
76  }
77 
82  explicit FileInputSource( std::string const& file_name, FILE* file )
83  : file_( file )
84  , file_name_( file_name )
85  {
86  // We do our own buffering.
87  std::setvbuf( file_, nullptr, _IONBF, 0 );
88  }
89 
90  FileInputSource( FileInputSource const& ) = default;
91  FileInputSource( FileInputSource&& ) = default;
92 
93  FileInputSource& operator= ( FileInputSource const& ) = default;
95 
96  ~FileInputSource() override = default;
97 
98  // -------------------------------------------------------------
99  // Overloaded Internal Members
100  // -------------------------------------------------------------
101 
102 private:
103 
107  size_t read_( char* buffer, size_t size ) override
108  {
109  // Special case: we already finished reading the file.
110  // We need this check as otherwise the file would be reopened again and
111  // read again from the start.
112  if( finished_ ) {
113  return 0;
114  }
115 
116  // We need to do lazy loading, otherwise, we might end up having too many open files
117  // if we are using the from_files() function, which opens all files at once...
118  if( file_ == nullptr ) {
119  errno = 0;
120  file_ = std::fopen( file_name_.c_str(), "rb" );
121 
122  if( file_ == nullptr ) {
123  throw std::runtime_error(
124  "Cannot open file " + file_name_ + ": " + std::string( strerror( errno ))
125  );
126  }
127 
128  // We do our own buffering.
129  std::setvbuf( file_, nullptr, _IONBF, 0 );
130  }
131 
132  // Do the reading.
133  size_t const ret = std::fread( buffer, 1, size, file_ );
134  if( std::ferror( file_ ) ) {
135  throw std::runtime_error( "Cannot read from file: " + file_name_ );
136  }
137 
138  // Similarly, we need to close again once we are done, so that the file is not kept
139  // open unnecessarily long after reading.
140  if( ret < size ) {
141  std::fclose( file_ );
142  file_ = nullptr;
143  finished_ = true;
144  }
145 
146  return ret;
147  }
148 
152  std::string source_name_() const override
153  {
154  return "input file (" + file_name_ + ")";
155  }
156 
160  std::string source_string_() const override
161  {
162  return file_name_;
163  }
164 
165  // -------------------------------------------------------------
166  // Member Variables
167  // -------------------------------------------------------------
168 
169  FILE* file_ = nullptr;
170  std::string file_name_;
171  bool finished_ = false;
172 };
173 
174 } // namespace utils
175 } // namespace genesis
176 
177 #endif // include guard
~FileInputSource() override=default
Input source for reading byte data from a file.
FileInputSource & operator=(FileInputSource const &)=default
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
bool file_exists(std::string const &filename)
Return true iff the file exists.
Definition: fs.cpp:78
Provides functions for accessing the file system.
Abstract base class for reading byte data from input sources.
FileInputSource(std::string const &file_name)
Construct the input source from a file with the given file name.
FileInputSource(std::string const &file_name, FILE *file)
Construct the input source from a FILE pointer. The file_name is used for the source_name() function ...