Loading...
Searching...
No Matches
fstreamPointers.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011 OpenFOAM Foundation
9 Copyright (C) 2018-2024 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "fstreamPointer.H"
30#include "OCountStream.H"
31#include "OSspecific.H"
32#include <cstdio>
33
34// HAVE_LIBZ defined externally
35// #define HAVE_LIBZ
37#ifdef HAVE_LIBZ
38#include "gzstream.h"
39#endif /* HAVE_LIBZ */
40
41// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
42
44{
45 #ifdef HAVE_LIBZ
46 return true;
47 #else
48 return false;
49 #endif
50}
51
52
54{
55 #ifdef HAVE_LIBZ
56 return true;
57 #else
58 return false;
59 #endif
60}
61
62
63// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
64
66(
67 const fileName& pathname,
68 IOstreamOption streamOpt // Currently unused
69)
71 ptr_()
72{
73 open(pathname, streamOpt);
74}
75
76
78(
79 const fileName& pathname
80)
82 ptr_()
83{
84 open(pathname);
85}
86
87
89:
90 ptr_(),
91 mode_(modeType::NONE)
92{}
93
94
96:
97 ptr_(new Foam::ocountstream),
98 mode_(modeType::NONE)
99{}
100
101
103(
104 const fileName& pathname,
105 IOstreamOption streamOpt,
107 bool atomic
108)
109:
110 ptr_(),
111 mode_(modeType::NONE)
112{
113 // Leave std::ios_base::trunc implicitly handled to make things
114 // easier for append mode.
115
116 std::ios_base::openmode openmode
117 (
118 std::ios_base::out | std::ios_base::binary
119 );
120
122 {
123 openmode |= std::ios_base::app;
124
125 // Cannot append to gzstream
127
128 // Cannot use append + atomic operation, without lots of extra work
129 atomic = false;
130 }
132 {
133 // Handle an "append-like" mode by opening "r+b" and NOT as "ab"
134 // - file already exists: Sets read position to start
135 // - file does not exist: Error
136
137 openmode |= std::ios_base::in; // [SIC] - use read bit, not append!
138
139 // Cannot append to gzstream
141
142 // Cannot use append + atomic operation, without lots of extra work
143 atomic = false;
144 }
145
146
147 // When opening new files, remove file variants out of the way.
148 // Eg, opening "file1"
149 // - remove old "file1.gz" (compressed)
150 // - also remove old "file1" if it is a symlink and we are not appending
151 //
152 // Not writing into symlinked files avoids problems with symlinked
153 // initial fields (eg, 0/U -> ../0.orig/U)
154
155 const fileName pathname_gz(pathname + ".gz");
156 const fileName pathname_tmp(pathname + "~tmp~");
157
159
160 if (IOstreamOption::COMPRESSED == streamOpt.compression())
161 {
162 // Output compression requested.
163
164 #ifdef HAVE_LIBZ
165 // TBD:
166 // atomic = true; // Always treat COMPRESSED like an atomic
167
168 const fileName& target = (atomic ? pathname_tmp : pathname_gz);
169
170 // Remove old uncompressed version (if any)
171 fType = Foam::type(pathname, false);
172 if (fType == fileName::SYMLINK || fType == fileName::FILE)
173 {
174 Foam::rm(pathname);
175 }
176
177 // Avoid writing into symlinked files (non-append mode)
178 if (atomic || (append == IOstreamOption::NO_APPEND))
179 {
180 fType = Foam::type(target, false);
181 if (fType == fileName::SYMLINK)
182 {
183 Foam::rm(target);
184 }
185 }
186
187 ptr_.reset(new ogzstream(target, openmode));
188
189 #else /* HAVE_LIBZ */
190
192
193 Warning
194 << nl
195 << "No write support for gz compressed files (libz)"
196 << " : downgraded to UNCOMPRESSED" << nl
197 << "file: " << pathname_gz << endl;
198
199 #endif /* HAVE_LIBZ */
200 }
201
202 if (IOstreamOption::COMPRESSED != streamOpt.compression())
203 {
204 const fileName& target = (atomic ? pathname_tmp : pathname);
205
206 // Remove old compressed version (if any)
207 fType = Foam::type(pathname_gz, false);
208 if (fType == fileName::SYMLINK || fType == fileName::FILE)
209 {
210 Foam::rm(pathname_gz);
211 }
212
213 // Avoid writing into symlinked files (non-append mode)
214 if (atomic || (append == IOstreamOption::NO_APPEND))
215 {
216 fType = Foam::type(target, false);
217 if (fType == fileName::SYMLINK)
218 {
219 Foam::rm(target);
220 }
221 }
222
223 // File pointer (std::ofstream)
224 auto filePtr = std::make_unique<std::ofstream>(target, openmode);
225
227 {
228 // Final handling for append 'app' (always non-atomic)
229
230 // Set output position to the end (like std::ios_base::ate)
231 // but only to test if the file had a size.
232 // No real performance problem since any subsequent write
233 // will do the same anyhow.
234
235 filePtr->seekp(0, std::ios_base::end);
236 if (filePtr->tellp() <= 0)
237 {
238 // Did not open an existing file
240 }
241 }
243 {
244 // Final handling for append 'ate' (always non-atomic)
245
246 if (filePtr->good())
247 {
248 // Success if file already exists.
249 // Set output position to the end - like std::ios_base::ate
250
251 filePtr->seekp(0, std::ios_base::end);
252
253 if (filePtr->tellp() <= 0)
254 {
255 // Did not open an existing file
257 }
258 }
259 else
260 {
261 // Error if file does not already exist.
262 // Reopen as regular output mode only.
263
264 // Did not open an existing file
266
267 if (filePtr->is_open())
268 {
269 filePtr->close();
270 }
271 filePtr->clear();
272 filePtr->open
273 (
274 target,
275 (std::ios_base::out | std::ios_base::binary)
276 );
277 }
278 }
279 ptr_.reset(filePtr.release());
280 }
281
282 // Is appending to an existing file
284 {
285 mode_ = modeType::APPENDING;
286 }
287
288 // An atomic output operation (normally not appending!)
289 if (atomic)
290 {
291 mode_ |= modeType::ATOMIC;
292 }
293}
294
295
297(
298 const fileName& pathname,
301 bool atomic
302)
303:
304 ofstreamPointer
305 (
306 pathname,
307 IOstreamOption(IOstreamOption::ASCII, comp),
308 append,
309 atomic
310 )
311{}
312
313
314// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
315
317(
318 const fileName& pathname,
319 IOstreamOption streamOpt // Currently unused
320)
321{
322 // Forcibly close old stream (if any)
323 ptr_.reset(nullptr);
324
325 const std::ios_base::openmode openmode
326 (
327 std::ios_base::in | std::ios_base::binary
328 );
329
330 ptr_.reset(new std::ifstream(pathname, openmode));
331
332 if (!ptr_->good())
333 {
334 // Try compressed version instead
335
336 const fileName pathname_gz(pathname + ".gz");
337
338 if (Foam::isFile(pathname_gz, false))
339 {
340 #ifdef HAVE_LIBZ
341
342 ptr_.reset(new igzstream(pathname_gz, openmode));
343
344 #else /* HAVE_LIBZ */
345
347 << "No read support for gz compressed files (libz)"
348 << " : could use 'gunzip' from the command-line" << nl
349 << "file: " << pathname_gz << endl
350 << exit(FatalError);
351
352 #endif /* HAVE_LIBZ */
353 }
354 else
355 {
356 // TBD:
357 // Can also fallback and open .orig files too
358 //
359 // auto* file = dynamic_cast<std::ifstream*>(ptr_.get());
360 // file->open(pathname + ".orig", mode);
361 }
362 }
363}
364
365
366void Foam::ifstreamPointer::reopen_gz(const std::string& pathname)
367{
368 #ifdef HAVE_LIBZ
369 auto* gz = dynamic_cast<igzstream*>(ptr_.get());
370
371 if (gz)
372 {
373 // Special treatment for gzstream
374 gz->close();
375 gz->clear();
376
377 gz->open
378 (
379 pathname + ".gz",
380 (std::ios_base::in | std::ios_base::binary)
381 );
382 return;
383 }
384 #endif /* HAVE_LIBZ */
385}
386
387
388void Foam::ofstreamPointer::reopen(const std::string& pathname)
389{
390 #ifdef HAVE_LIBZ
391 auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
392
393 if (gz)
394 {
395 // Special treatment for gzstream
396 gz->close();
397 gz->clear();
398
399 if (mode_ & modeType::ATOMIC)
400 {
401 gz->open
402 (
403 pathname + "~tmp~",
404 (std::ios_base::out | std::ios_base::binary)
405 );
406 }
407 else
408 {
409 gz->open
410 (
411 pathname + ".gz",
412 (std::ios_base::out | std::ios_base::binary)
413 );
414 }
415 return;
416 }
417 #endif /* HAVE_LIBZ */
418
419 auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
420
421 if (file)
422 {
423 if (file->is_open())
424 {
425 file->close();
426 }
427 file->clear();
428
429 // Invalidate the appending into existing file information
430 // since rewind usually means overwrite
431 mode_ &= ~modeType::APPENDING;
432
433 if (mode_ & modeType::ATOMIC)
434 {
435 file->open
436 (
437 pathname + "~tmp~",
438 (std::ios_base::out | std::ios_base::binary)
439 );
440 }
441 else
442 {
443 file->open
444 (
445 pathname,
446 (std::ios_base::out | std::ios_base::binary)
447 );
448 }
449 return;
450 }
451}
452
453
454void Foam::ofstreamPointer::close(const std::string& pathname)
455{
456 // Invalidate the appending into existing file information
457 mode_ &= ~modeType::APPENDING;
458
459 if (pathname.empty() || !(mode_ & modeType::ATOMIC))
460 {
461 return;
462 }
463
464 #ifdef HAVE_LIBZ
465 auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
466
467 if (gz)
468 {
469 // Special treatment for gzstream
470 gz->close();
471 gz->clear();
472
473 std::rename
474 (
475 (pathname + "~tmp~").c_str(),
476 (pathname + ".gz").c_str()
477 );
478 return;
479 }
480 #endif /* HAVE_LIBZ */
481
482 auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
483
484 if (file)
485 {
486 if (file->is_open())
487 {
488 file->close();
489 }
490 file->clear();
491
492 std::rename
493 (
494 (pathname + "~tmp~").c_str(),
495 pathname.c_str()
496 );
497 return;
498 }
499}
500
501
504{
505 #ifdef HAVE_LIBZ
506 if (dynamic_cast<const igzstream*>(ptr_.get()))
507 {
509 }
510 #endif /* HAVE_LIBZ */
511
513}
514
515
518{
519 #ifdef HAVE_LIBZ
520 if (dynamic_cast<const ogzstream*>(ptr_.get()))
521 {
523 }
524 #endif /* HAVE_LIBZ */
525
527}
528
529
530// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
A simple container for options an IOstream can normally have.
compressionType compression() const noexcept
Get the stream compression.
compressionType
Compression treatment (UNCOMPRESSED | COMPRESSED).
@ UNCOMPRESSED
compression = false
@ COMPRESSED
compression = true
appendType
File appending (NO_APPEND | APPEND_APP | APPEND_ATE).
@ NO_APPEND
no append (truncates existing)
@ APPEND_ATE
append (seek end after open)
@ APPEND_APP
append (seek end each write)
A class for handling file names.
Definition fileName.H:75
Type
Enumerations to handle directory entry types.
Definition fileName.H:82
@ SYMLINK
A symbolic link.
Definition fileName.H:86
@ UNDEFINED
Undefined type.
Definition fileName.H:83
@ FILE
A regular file.
Definition fileName.H:84
static bool supports_gz() noexcept
True if compiled with libz support.
void open(const fileName &pathname, IOstreamOption streamOpt=IOstreamOption())
Attempts to open the specified file for reading.
void reopen_gz(const std::string &pathname)
Special 'rewind' method for compressed stream.
IOstreamOption::compressionType whichCompression() const
Which compression type?
ifstreamPointer() noexcept=default
Default construct (empty).
Trivial output stream for calculating byte counts.
static bool supports_gz() noexcept
True if compiled with libz support.
ofstreamPointer(const ofstreamPointer &)=delete
No copy construct.
void reopen(const std::string &pathname)
Reopen for compressed/non-compressed. Discards append status.
IOstreamOption::compressionType whichCompression() const
Which compression type?
void close(const std::string &pathname)
Close stream and rename file.
ofstreamPointer() noexcept
Default construct (empty).
rAUs append(new volScalarField(IOobject::groupName("rAU", phase1.name()), 1.0/(U1Eqn.A()+byDt(max(phase1.residualAlpha() - alpha1, scalar(0)) *rho1))))
Namespace for OpenFOAM.
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition POSIX.C:1406
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition POSIX.C:801
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
const direction noexcept
Definition scalarImpl.H:265
bool isFile(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition POSIX.C:879
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional 'FOAM Warning' header text.
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
autoPtr< OFstream > filePtr