1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 | // *****************************************************************************
/*!
\file src/Base/Reader.cpp
\copyright 2012-2015 J. Bakosi,
2016-2018 Los Alamos National Security, LLC.,
2019-2021 Triad National Security, LLC.,
2022-2024 J. Bakosi
All rights reserved. See the LICENSE file for details.
\brief Reader class definition
\details Reader base class declaration. Reader base servers as a base class
for various file readers. It does generic low-level I/O, e.g., opening and
closing a file, and associated error handling.
*/
// *****************************************************************************
#include <cstdio>
#include <exception>
#include <string>
#include "Reader.hpp"
#include "Exception.hpp"
using tk::Reader;
Reader::Reader( const std::string& filename, std::ios_base::openmode mode ) :
m_filename( filename ), m_inFile()
// *****************************************************************************
// Constructor: Acquire file handle
//! \param[in] filename Name of file to open for reading
//! \param[in] mode Open mode, see
//! http://en.cppreference.com/w/cpp/io/ios_base/openmode
// *****************************************************************************
{
// Make sure there is a filename
Assert( !filename.empty(), "No filename specified" );
// Check if file exists, throw exception if it does not
m_inFile.open( filename, mode );
ErrChk( m_inFile.good(), "Failed to open file: " + filename );
// Attempt to read a character, throw if it fails
// It is curious that on some systems opening a directory instead of a file
// with the above ifstream::open() call does not set the failbit. Thus we get
// here fine, so we try to read a character from it. If it is a directory or
// an empty file the read will fail, so we throw. Read more at: http://
// stackoverflow.com/questions/9591036/
// ifstream-open-doesnt-set-error-bits-when-argument-is-a-directory.
m_inFile.get();
ErrChk( m_inFile.good(), "Failed to read from file: " + filename );
// Close it
m_inFile.close();
ErrChk( !m_inFile.fail(), "Failed to close file: " + filename );
// Re-open
m_inFile.open( filename, std::ifstream::in );
ErrChk( m_inFile.good(), "Failed to open file: " + filename );
}
Reader::~Reader() noexcept
// *****************************************************************************
// Destructor: Release file handle
//! \details Exception safety: no-throw guarantee: never throws exceptions.
//! Error handling, while done by throwing and catching exceptions, results in
//! warnings to terminal. We use C-style printf, since that will not throw
//! exceptions.
// *****************************************************************************
{
// Clear failbit triggered by eof, so close() won't throw a false FAILED_CLOSE
m_inFile.clear();
try {
m_inFile.close();
ErrChk( !m_inFile.fail(), "Failed to close file: " + m_filename );
} // emit only a warning on error
catch (Exception& e) {
e.handleException();
}
catch (std::exception& e) {
printf( ">>> WARNING: std::exception in MeshReader destructor: %s\n",
e.what() );
}
catch (...) {
printf( ">>> WARNING: UNKNOWN EXCEPTION in MeshReader destructor\n" );
}
}
std::string
Reader::firstline()
// *****************************************************************************
// Return first line (for detection of file type based on header)
//! \return First line read from file. This can be used for detection of file
//! type based on header.
// *****************************************************************************
{
std::string s;
std::getline( m_inFile, s ); // read the first line
m_inFile.seekg( 0, std::ios::beg ); // seek back to the beginning of file
return s;
}
std::string
Reader::line( std::size_t lineNum )<--- The function 'line' is never used.
// *****************************************************************************
// Read a given line from file
//! \param[in] lineNum Line number to read from file
//! \return Line read from file at line given
// *****************************************************************************
{
std::string s;
std::size_t num = 0;
while ( std::getline( m_inFile, s ) && ++num < lineNum ) {}
m_inFile.seekg( 0, std::ios::beg ); // seek back to the beginning of file
return s;
}
|