mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
fileUtils.cpp
Go to the documentation of this file.
1/** \file fileUtils.cpp
2 * \brief Definitions of utilities for working with files
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup fileutils
7 *
8 */
9
10//***********************************************************************//
11// Copyright 2020 Jared R. Males (jaredmales@gmail.com)
12//
13// This file is part of mxlib.
14//
15// mxlib is free software: you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation, either version 3 of the License, or
18// (at your option) any later version.
19//
20// mxlib is distributed in the hope that it will be useful,
21// but WITHOUT ANY WARRANTY; without even the implied warranty of
22// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23// GNU General Public License for more details.
24//
25// You should have received a copy of the GNU General Public License
26// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
27//***********************************************************************//
28
29#include "ioutils/fileUtils.hpp"
30
31#include <iostream>
32#include <string>
33#include <vector>
34#include <sstream>
35#include <libgen.h>
36#include <cmath>
37#include <algorithm>
38
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <unistd.h>
42
43#include <filesystem>
44
45#include "../../include/mxException.hpp"
46
47namespace mx
48{
49namespace ioutils
50{
51
52bool exists( const std::string &path )
53{
54 return std::filesystem::exists( std::filesystem::path( path ) );
55}
56
57int createDirectories( const std::string &path )
58{
59 // Use the non throwing version and silently ignore EEXIST errors
60 std::error_code ec;
61 std::filesystem::create_directories( path, ec );
62 if( ec.value() != 0 && ec.value() != EEXIST )
63 {
64 return -1;
65 }
66
67 return 0;
68}
69
70std::string pathStem( const std::string &fname )
71{
72 std::filesystem::path p( fname );
73 return p.stem().string();
74}
75
76std::string pathFilename( const std::string &fname )
77{
78 std::filesystem::path p( fname );
79 return p.filename().string();
80}
81
82std::string parentPath( const std::string &fname )
83{
84 std::filesystem::path p( fname );
85 return p.parent_path().string();
86}
87
88namespace impl
89{
90template <class verboseT>
91error_t getFileNames( std::vector<std::string> &fileNames,
92 const std::string &directory,
93 const std::string &prefix,
94 const std::string &substr,
95 const std::string &extension )
96{
97 try // there are several things that can throw here
98 {
99 fileNames.clear();
100
101 if( std::filesystem::exists( directory ) )
102 {
103 if( std::filesystem::is_directory( directory ) )
104 {
105 bool hasext = false;
106 std::string _ext;
107 if( extension.size() > 0 )
108 {
109 if( extension[0] != '.' )
110 {
111 _ext = '.';
112 }
113
114 _ext += extension;
115
116 hasext = true;
117 }
118
119 bool hasprefix = ( prefix.size() > 0 );
120
121 bool hassub = ( substr.size() > 0 );
122
123 std::filesystem::directory_iterator it{ directory };
124 auto it_end = std::filesystem::directory_iterator{};
125 for( it; it != it_end; ++it )
126 {
127 if( hasext )
128 {
129 if( it->path().extension() != _ext )
130 {
131 continue;
132 }
133 }
134
135 std::string p = it->path().filename().generic_string();
136
137 if( hasprefix )
138 {
139 if( p.size() < prefix.size() )
140 {
141 continue;
142 }
143 else
144 {
145 // This won't throw because:
146 // - prefix has size > 0
147 // - p.size() >= prefix.size()
148 // - therefore prefix.size() > 0
149 // - so pos1 = 0 will not throw.
150 if( p.compare( 0, prefix.size(), prefix ) != 0 )
151 {
152 continue;
153 }
154 }
155 }
156
157 if( hassub )
158 {
159 if( p.size() < 2 )
160 {
161 continue;
162 }
163
164 size_t sspos = p.find( substr, 1 ); // only match if not prefix
165
166 if( sspos == std::string::npos )
167 {
168 continue;
169 }
170 }
171
172 // If here then it passed all checks
173 // this could throw
174 fileNames.push_back( it->path().native() );
175 }
176
177 sort( fileNames.begin(), fileNames.end() );
178 }
179 else
180 {
181 return internal::mxlib_error_report<verboseT>( error_t::invalidarg, directory + " is not a directory" );
182 }
183 }
184 else
185 {
186 return internal::mxlib_error_report<verboseT>( error_t::dirnotfound, directory + " was not found" );
187 }
188
189 return error_t::noerror;
190 }
191 catch( const std::exception &e )
192 {
193 return internal::mxlib_error_report<verboseT>( error_t::exception, e.what() );
194 }
195 catch( ... )
196 {
197 return internal::mxlib_error_report<verboseT>( error_t::exception );
198 }
199}
200} // namespace impl
201
202template <>
203error_t getFileNames<verbose::o>( std::vector<std::string> &fileNames,
204 const std::string &directory,
205 const std::string &prefix,
206 const std::string &substr,
207 const std::string &extension )
208{
209 return impl::getFileNames<verbose::o>( fileNames, directory, prefix, substr, extension );
210}
211
212template <>
213error_t getFileNames<verbose::v>( std::vector<std::string> &fileNames,
214 const std::string &directory,
215 const std::string &prefix,
216 const std::string &substr,
217 const std::string &extension )
218{
219 return impl::getFileNames<verbose::v>( fileNames, directory, prefix, substr, extension );
220}
221
222template <>
223error_t getFileNames<verbose::vv>( std::vector<std::string> &fileNames,
224 const std::string &directory,
225 const std::string &prefix,
226 const std::string &substr,
227 const std::string &extension )
228{
229 return impl::getFileNames<verbose::vv>( fileNames, directory, prefix, substr, extension );
230}
231
232template <>
233error_t getFileNames<verbose::vvv>( std::vector<std::string> &fileNames,
234 const std::string &directory,
235 const std::string &prefix,
236 const std::string &substr,
237 const std::string &extension )
238{
239 return impl::getFileNames<verbose::vvv>( fileNames, directory, prefix, substr, extension );
240}
241
242std::string fileNamePrependAppend( const std::string &fname, const std::string &prepend, const std::string &append )
243{
244 std::string dir, base, ext;
245
246 std::filesystem::path p = fname;
247 dir = p.parent_path().string();
248 base = p.stem().string();
249 ext = p.extension().string();
250
251 return dir + '/' + prepend + base + append + ext;
252}
253
254std::string fileNameAppend( const std::string &fname, const std::string &append )
255{
256 return fileNamePrependAppend( fname, "", append );
257}
258
259std::string fileNamePrepend( const std::string &fname, const std::string &prepend )
260{
261 return fileNamePrependAppend( fname, prepend, "" );
262}
263
264std::string
265getSequentialFilename( const std::string &basename, const std::string &extension, const int startat, const int ndigit )
266{
267 // int maxdig = 1;
268 // for(int j=0;j<ndigit;++j) maxdig *= 10;
269 int maxdig = pow( 10, ndigit );
270
271 char formstr[64];
272 snprintf( formstr, sizeof( formstr ), "%%0%dd", ndigit );
273
274 char digstr[64];
275 int i = startat;
276
277 std::stringstream outn;
278
279 snprintf( digstr, sizeof( digstr ), formstr, i );
280
281 outn << basename;
282 outn << digstr;
283 outn << extension;
284
285 while( std::filesystem::exists( outn.str() ) && i < maxdig )
286 {
287 ++i;
288 outn.str( "" );
289
290 snprintf( digstr, sizeof( digstr ), formstr, i );
291
292 outn << basename;
293 outn << digstr;
294
295 outn << extension;
296 }
297
298 return outn.str();
299}
300
301off_t fileSize( int fd )
302{
303 if( fd == -1 )
304 {
305 return -1;
306 }
307
308 struct stat stbuf;
309
310 if( ( fstat( fd, &stbuf ) != 0 ) || ( !S_ISREG( stbuf.st_mode ) ) )
311 {
312 return -1;
313 }
314
315 return stbuf.st_size;
316}
317
318off_t fileSize( FILE *f )
319{
320 return fileSize( fileno( f ) );
321}
322
323} // namespace ioutils
324} // namespace mx
Declarations of utilities for working with files.
error_t
The mxlib error codes.
Definition error_t.hpp:20
@ noerror
No error has occurred.
@ dirnotfound
The directory was not found.
@ exception
An exception was thrown.
@ invalidarg
An argument was invalid.
std::string fileNamePrepend(const std::string &fname, const std::string &prepend)
Prepend strings to a file name, leaving the directory and extension unaltered.
std::string getSequentialFilename(const std::string &basename, const std::string &extension="", const int startat=0, int ndigit=4)
Get the next file in a numbered sequence.
std::string fileNamePrependAppend(const std::string &fname, const std::string &prepend, const std::string &append)
Prepend and/or append strings to a file name, leaving the directory and extension unaltered.
std::string fileNameAppend(const std::string &fname, const std::string &append)
Append a string to a file name, leaving the directory and extension unaltered.
int createDirectories(const std::string &path)
Create a directory or directories.
Definition fileUtils.cpp:57
std::string parentPath(const std::string &fname)
Get the parent path from a filename.
Definition fileUtils.cpp:82
std::string pathStem(const std::string &fname)
Get the stem of the filename.
Definition fileUtils.cpp:70
bool exists(const std::string &path)
Check if a path exists.
Definition fileUtils.cpp:52
off_t fileSize(int fd)
Get the size in bytes of a file.
std::string pathFilename(const std::string &fname)
Get the base filename.
Definition fileUtils.cpp:76
The mxlib c++ namespace.
Definition mxError.hpp:40