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-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
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
36 
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 // Future: List<char> slurpFile(....);
64 
65 
66 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
67 
69 (
70  const fileName& pathname,
71  IOstreamOption streamOpt // Currently unused
72 )
73 :
74  ptr_(nullptr)
75 {
76  open(pathname, streamOpt);
77 }
78 
79 
81 (
82  const fileName& pathname
83 )
84 :
85  ptr_(nullptr)
86 {
87  open(pathname);
88 }
89 
90 
92 :
93  ptr_(),
94  atomic_(false)
95 {}
96 
97 
99 :
100  ptr_(new Foam::ocountstream),
101  atomic_(false)
102 {}
103 
104 
106 (
107  const fileName& pathname,
108  IOstreamOption streamOpt,
109  const bool append,
110  const bool atomic
111 )
112 :
113  ptr_(nullptr),
114  atomic_(atomic)
115 {
116  std::ios_base::openmode mode
117  (
118  std::ios_base::out | std::ios_base::binary
119  );
120 
121  if (append)
122  {
123  mode |= 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  }
131 
132 
133  // When opening new files, remove file variants out of the way.
134  // Eg, opening "file1"
135  // - remove old "file1.gz" (compressed)
136  // - also remove old "file1" if it is a symlink and we are not appending
137  //
138  // Not writing into symlinked files avoids problems with symlinked
139  // initial fields (eg, 0/U -> ../0.orig/U)
140 
141  const fileName pathname_gz(pathname + ".gz");
142  const fileName pathname_tmp(pathname + "~tmp~");
143 
144  fileName::Type fType = fileName::Type::UNDEFINED;
145 
146  if (IOstreamOption::COMPRESSED == streamOpt.compression())
147  {
148  // Output compression requested.
149 
150  #ifdef HAVE_LIBZ
151  // TBD:
152  // atomic_ = true; // Always treat COMPRESSED like an atomic
153 
154  const fileName& target = (atomic_ ? pathname_tmp : pathname_gz);
155 
156  // Remove old uncompressed version (if any)
157  fType = Foam::type(pathname, false);
158  if (fType == fileName::SYMLINK || fType == fileName::FILE)
159  {
160  Foam::rm(pathname);
161  }
162 
163  // Avoid writing into symlinked files (non-append mode)
164  if (!append || atomic_)
165  {
166  fType = Foam::type(target, false);
167  if (fType == fileName::SYMLINK)
168  {
169  Foam::rm(target);
170  }
171  }
172 
173  ptr_.reset(new ogzstream(target, mode));
174 
175  #else /* HAVE_LIBZ */
176 
178 
179  Warning
180  << nl
181  << "No write support for gz compressed files (libz)"
182  << " : downgraded to UNCOMPRESSED" << nl
183  << "file: " << pathname_gz << endl;
184 
185  #endif /* HAVE_LIBZ */
186  }
187 
188  if (IOstreamOption::COMPRESSED != streamOpt.compression())
189  {
190  const fileName& target = (atomic_ ? pathname_tmp : pathname);
191 
192  // Remove old compressed version (if any)
193  fType = Foam::type(pathname_gz, false);
194  if (fType == fileName::SYMLINK || fType == fileName::FILE)
195  {
196  Foam::rm(pathname_gz);
197  }
198 
199  // Avoid writing into symlinked files (non-append mode)
200  if (!append || atomic_)
201  {
202  fType = Foam::type(target, false);
203  if (fType == fileName::SYMLINK)
204  {
205  Foam::rm(target);
206  }
207  }
209  ptr_.reset(new std::ofstream(target, mode));
210  }
211 }
212 
213 
215 (
216  const fileName& pathname,
218  const bool append,
219  const bool atomic
220 )
221 :
222  ofstreamPointer
223  (
224  pathname,
225  IOstreamOption(IOstreamOption::ASCII, comp),
226  append,
227  atomic
228  )
229 {}
230 
231 
232 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
233 
235 (
236  const fileName& pathname,
237  IOstreamOption streamOpt // Currently unused
238 )
239 {
240  // Forcibly close old stream (if any)
241  ptr_.reset(nullptr);
242 
243  const std::ios_base::openmode mode
244  (
245  std::ios_base::in | std::ios_base::binary
246  );
247 
248  ptr_.reset(new std::ifstream(pathname, mode));
249 
250  if (!ptr_->good())
251  {
252  // Try compressed version instead
253 
254  const fileName pathname_gz(pathname + ".gz");
255 
256  if (Foam::isFile(pathname_gz, false))
257  {
258  #ifdef HAVE_LIBZ
259 
260  ptr_.reset(new igzstream(pathname_gz, mode));
261 
262  #else /* HAVE_LIBZ */
263 
264  FatalError
265  << "No read support for gz compressed files (libz)"
266  << " : could use 'gunzip' from the command-line" << nl
267  << "file: " << pathname_gz << endl
268  << exit(FatalError);
269 
270  #endif /* HAVE_LIBZ */
271  }
272  else
273  {
274  // TBD:
275  // Can also fallback and open .orig files too
276  //
277  // auto* file = dynamic_cast<std::ifstream*>(ptr_.get());
278  // file->open(pathname + ".orig", mode);
279  }
280  }
281 }
282 
283 
284 void Foam::ifstreamPointer::reopen_gz(const std::string& pathname)
285 {
286  #ifdef HAVE_LIBZ
287  auto* gz = dynamic_cast<igzstream*>(ptr_.get());
288 
289  if (gz)
290  {
291  // Special treatment for gzstream
292  gz->close();
293  gz->clear();
294 
295  gz->open
296  (
297  pathname + ".gz",
298  (std::ios_base::in | std::ios_base::binary)
299  );
300  return;
301  }
302  #endif /* HAVE_LIBZ */
303 }
304 
305 
306 void Foam::ofstreamPointer::reopen(const std::string& pathname)
307 {
308  #ifdef HAVE_LIBZ
309  auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
310 
311  if (gz)
312  {
313  // Special treatment for gzstream
314  gz->close();
315  gz->clear();
316 
317  if (atomic_)
318  {
319  gz->open
320  (
321  pathname + "~tmp~",
322  (std::ios_base::out | std::ios_base::binary)
323  );
324  }
325  else
326  {
327  gz->open
328  (
329  pathname + ".gz",
330  (std::ios_base::out | std::ios_base::binary)
331  );
332  }
333  return;
334  }
335  #endif /* HAVE_LIBZ */
336 
337  auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
338 
339  if (file)
340  {
341  if (file->is_open())
342  {
343  file->close();
344  }
345  file->clear();
346 
347  // Don't need original request to append since rewind implies
348  // trashing that anyhow.
349 
350  if (atomic_)
351  {
352  file->open
353  (
354  pathname + "~tmp~",
355  (std::ios_base::out | std::ios_base::binary)
356  );
357  }
358  else
359  {
360  file->open
361  (
362  pathname,
363  (std::ios_base::out | std::ios_base::binary)
364  );
365  }
366  return;
367  }
368 }
369 
370 
371 void Foam::ofstreamPointer::close(const std::string& pathname)
372 {
373  if (!atomic_ || pathname.empty()) return;
374 
375  #ifdef HAVE_LIBZ
376  auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
377 
378  if (gz)
379  {
380  // Special treatment for gzstream
381  gz->close();
382  gz->clear();
383 
384  std::rename
385  (
386  (pathname + "~tmp~").c_str(),
387  (pathname + ".gz").c_str()
388  );
389  return;
390  }
391  #endif /* HAVE_LIBZ */
392 
393  auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
394 
395  if (file)
396  {
397  if (file->is_open())
398  {
399  file->close();
400  }
401  file->clear();
402 
403  std::rename
404  (
405  (pathname + "~tmp~").c_str(),
406  pathname.c_str()
407  );
408  return;
409  }
410 }
411 
412 
415 {
416  #ifdef HAVE_LIBZ
417  if (dynamic_cast<const igzstream*>(ptr_.get()))
418  {
419  return IOstreamOption::compressionType::COMPRESSED;
420  }
421  #endif /* HAVE_LIBZ */
422 
423  return IOstreamOption::compressionType::UNCOMPRESSED;
424 }
425 
426 
429 {
430  #ifdef HAVE_LIBZ
431  if (dynamic_cast<const ogzstream*>(ptr_.get()))
432  {
433  return IOstreamOption::compressionType::COMPRESSED;
434  }
435  #endif /* HAVE_LIBZ */
436 
437  return IOstreamOption::compressionType::UNCOMPRESSED;
438 }
439 
440 
441 // ************************************************************************* //
A symbolic link.
Definition: fileName.H:86
A class for handling file names.
Definition: fileName.H:72
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
compressionType
Compression treatment (UNCOMPRESSED | COMPRESSED)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
IOstreamOption::compressionType whichCompression() const
Which compression type?
Trivial output stream for calculating byte counts.
Definition: OCountStream.H:48
static bool supports_gz()
True if compiled with libz support.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
ofstreamPointer() noexcept
Default construct (empty)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static bool supports_gz()
True if compiled with libz support.
void reopen_gz(const std::string &pathname)
Special &#39;rewind&#39; method for compressed stream.
A simple container for options an IOstream can normally have.
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
A regular file.
Definition: fileName.H:84
void reopen(const std::string &pathname)
Reopen for compressed/non-compressed.
const direction noexcept
Definition: Scalar.H:258
ifstreamPointer() noexcept=default
Default construct (empty)
compressionType compression() const noexcept
Get the stream compression.
void close(const std::string &pathname)
Close stream and rename file.
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional &#39;FOAM Warning&#39; header text...
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:877
rAUs append(new volScalarField(IOobject::groupName("rAU", phase1.name()), 1.0/(U1Eqn.A()+byDt(max(phase1.residualAlpha() - alpha1, scalar(0)) *rho1))))
IOstreamOption::compressionType whichCompression() const
Which compression type?
void open(const fileName &pathname, IOstreamOption streamOpt=IOstreamOption())
Attempts to open the specified file for reading.
mode_t mode(const fileName &name, const bool followLink=true)
Return the file mode, normally following symbolic links.
Definition: POSIX.C:773
Type
Enumerations to handle directory entry types.
Definition: fileName.H:81
Namespace for OpenFOAM.
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: POSIX.C:1404