3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
33 * Implements gmx::File.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_utility
48 #include "gromacs/legacyheaders/futil.h"
50 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/gmxassert.h"
52 #include "gromacs/utility/stringutil.h"
58 * Private implementation class for File.
60 * \ingroup module_utility
66 * Initialize a file object with the given handle.
68 * \param[in] fp File handle to use (may be NULL).
69 * \param[in] bClose Whether this object should close its file handle.
71 Impl(FILE *fp, bool bClose);
74 //! File handle for this object (may be NULL).
77 * Whether \p fp_ should be closed by this object.
79 * Can be true if \p fp_ is NULL.
84 File::Impl::Impl(FILE *fp, bool bClose)
85 : fp_(fp), bClose_(bClose)
91 if (fp_ != NULL && bClose_)
95 // TODO: Log the error somewhere
100 File::File(const char *filename, const char *mode)
101 : impl_(new Impl(NULL, true))
103 open(filename, mode);
106 File::File(const std::string &filename, const char *mode)
107 : impl_(new Impl(NULL, true))
109 open(filename, mode);
112 File::File(FILE *fp, bool bClose)
113 : impl_(new Impl(fp, bClose))
121 void File::open(const char *filename, const char *mode)
123 GMX_RELEASE_ASSERT(impl_->fp_ == NULL,
124 "Attempted to open the same file object twice");
125 // TODO: Port all necessary functionality from ffopen() here.
126 impl_->fp_ = fopen(filename, mode);
127 if (impl_->fp_ == NULL)
129 GMX_THROW_WITH_ERRNO(
130 FileIOError(formatString("Could not open file '%s'", filename)),
135 void File::open(const std::string &filename, const char *mode)
137 open(filename.c_str(), mode);
142 GMX_RELEASE_ASSERT(impl_->fp_ != NULL,
143 "Attempted to close a file object that is not open");
144 GMX_RELEASE_ASSERT(impl_->bClose_,
145 "Attempted to close a file object that should not be");
146 bool bOk = (fclose(impl_->fp_) == 0);
150 GMX_THROW_WITH_ERRNO(
151 FileIOError("Error while closing file"), "fclose", errno);
157 GMX_RELEASE_ASSERT(impl_->fp_ != NULL,
158 "Attempted to access a file object that is not open");
162 void File::readBytes(void *buffer, size_t bytes)
166 // TODO: Retry based on errno or something else?
167 size_t bytesRead = std::fread(buffer, 1, bytes, fp);
168 if (bytesRead != bytes)
172 GMX_THROW(FileIOError(
173 formatString("Premature end of file\n"
174 "Attempted to read: %d bytes\n"
175 "Successfully read: %d bytes",
176 static_cast<int>(bytes),
177 static_cast<int>(bytesRead))));
181 GMX_THROW_WITH_ERRNO(FileIOError("Error while reading file"),
187 bool File::readLine(std::string *line)
190 const size_t bufsize = 256;
195 while (fgets(buf, bufsize, fp) != NULL)
197 size_t length = std::strlen(buf);
198 result.append(buf, length);
199 if (length < bufsize - 1 || buf[length - 1] == '\n')
206 GMX_THROW_WITH_ERRNO(FileIOError("Error while reading file"),
210 return !result.empty() || !feof(fp);
213 void File::writeString(const char *str)
215 if (fprintf(handle(), "%s", str) < 0)
217 GMX_THROW_WITH_ERRNO(FileIOError("Writing to file failed"),
222 void File::writeLine(const char *line)
224 size_t length = std::strlen(line);
227 if (length == 0 || line[length-1] != '\n')
233 void File::writeLine()
239 bool File::exists(const char *filename)
241 return gmx_fexist(filename);
245 bool File::exists(const std::string &filename)
247 return exists(filename.c_str());
251 File &File::standardInput()
253 static File stdinObject(stdin, false);
258 File &File::standardOutput()
260 static File stdoutObject(stdout, false);
265 File &File::standardError()
267 static File stderrObject(stderr, false);
272 std::string File::readToString(const char *filename)
274 // Binary mode is required on Windows to be able to determine a size
275 // that can be passed to fread().
276 File file(filename, "rb");
277 FILE *fp = file.handle();
279 if (std::fseek(fp, 0L, SEEK_END) != 0)
281 GMX_THROW_WITH_ERRNO(FileIOError("Seeking to end of file failed"),
284 long len = std::ftell(fp);
287 GMX_THROW_WITH_ERRNO(FileIOError("Reading file length failed"),
290 if (std::fseek(fp, 0L, SEEK_SET) != 0)
292 GMX_THROW_WITH_ERRNO(FileIOError("Seeking to start of file failed"),
296 std::vector<char> data(len);
297 file.readBytes(&data[0], len);
300 std::string result(&data[0], len);
301 // The below is necessary on Windows to make newlines stay as '\n' on a
303 result = replaceAll(result, "\r\n", "\n");
309 std::string File::readToString(const std::string &filename)
311 return readToString(filename.c_str());
315 void File::writeFileFromString(const std::string &filename,
316 const std::string &text)
318 File file(filename, "w");
319 file.writeString(text);