openfoam/src/OpenFOAM/db/IOstreams/Fstreams/fstreamPointers.C
Mark Olesen e7f0628d79 ENH: promote IFstream::readContents() to public static function
- reads file contents into a DynamicList<char>, which can then be
  broadcast, moved to a ICharStream etc.
2024-03-06 15:05:36 +01:00

439 lines
9.9 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "fstreamPointer.H"
#include "OCountStream.H"
#include "OSspecific.H"
#include <cstdio>
// HAVE_LIBZ defined externally
// #define HAVE_LIBZ
#ifdef HAVE_LIBZ
#include "gzstream.h"
#endif /* HAVE_LIBZ */
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
bool Foam::ifstreamPointer::supports_gz() noexcept
{
#ifdef HAVE_LIBZ
return true;
#else
return false;
#endif
}
bool Foam::ofstreamPointer::supports_gz() noexcept
{
#ifdef HAVE_LIBZ
return true;
#else
return false;
#endif
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::ifstreamPointer::ifstreamPointer
(
const fileName& pathname,
IOstreamOption streamOpt // Currently unused
)
:
ptr_()
{
open(pathname, streamOpt);
}
Foam::ifstreamPointer::ifstreamPointer
(
const fileName& pathname
)
:
ptr_()
{
open(pathname);
}
Foam::ofstreamPointer::ofstreamPointer() noexcept
:
ptr_(),
atomic_(false)
{}
Foam::ofstreamPointer::ofstreamPointer(std::nullptr_t)
:
ptr_(new Foam::ocountstream),
atomic_(false)
{}
Foam::ofstreamPointer::ofstreamPointer
(
const fileName& pathname,
IOstreamOption streamOpt,
const bool append,
const bool atomic
)
:
ptr_(),
atomic_(atomic)
{
std::ios_base::openmode mode
(
std::ios_base::out | std::ios_base::binary
);
if (append)
{
mode |= std::ios_base::app;
// Cannot append to gzstream
streamOpt.compression(IOstreamOption::UNCOMPRESSED);
// Cannot use append + atomic operation, without lots of extra work
atomic_ = false;
}
// When opening new files, remove file variants out of the way.
// Eg, opening "file1"
// - remove old "file1.gz" (compressed)
// - also remove old "file1" if it is a symlink and we are not appending
//
// Not writing into symlinked files avoids problems with symlinked
// initial fields (eg, 0/U -> ../0.orig/U)
const fileName pathname_gz(pathname + ".gz");
const fileName pathname_tmp(pathname + "~tmp~");
fileName::Type fType = fileName::Type::UNDEFINED;
if (IOstreamOption::COMPRESSED == streamOpt.compression())
{
// Output compression requested.
#ifdef HAVE_LIBZ
// TBD:
// atomic_ = true; // Always treat COMPRESSED like an atomic
const fileName& target = (atomic_ ? pathname_tmp : pathname_gz);
// Remove old uncompressed version (if any)
fType = Foam::type(pathname, false);
if (fType == fileName::SYMLINK || fType == fileName::FILE)
{
Foam::rm(pathname);
}
// Avoid writing into symlinked files (non-append mode)
if (!append || atomic_)
{
fType = Foam::type(target, false);
if (fType == fileName::SYMLINK)
{
Foam::rm(target);
}
}
ptr_.reset(new ogzstream(target, mode));
#else /* HAVE_LIBZ */
streamOpt.compression(IOstreamOption::UNCOMPRESSED);
Warning
<< nl
<< "No write support for gz compressed files (libz)"
<< " : downgraded to UNCOMPRESSED" << nl
<< "file: " << pathname_gz << endl;
#endif /* HAVE_LIBZ */
}
if (IOstreamOption::COMPRESSED != streamOpt.compression())
{
const fileName& target = (atomic_ ? pathname_tmp : pathname);
// Remove old compressed version (if any)
fType = Foam::type(pathname_gz, false);
if (fType == fileName::SYMLINK || fType == fileName::FILE)
{
Foam::rm(pathname_gz);
}
// Avoid writing into symlinked files (non-append mode)
if (!append || atomic_)
{
fType = Foam::type(target, false);
if (fType == fileName::SYMLINK)
{
Foam::rm(target);
}
}
ptr_.reset(new std::ofstream(target, mode));
}
}
Foam::ofstreamPointer::ofstreamPointer
(
const fileName& pathname,
IOstreamOption::compressionType comp,
const bool append,
const bool atomic
)
:
ofstreamPointer
(
pathname,
IOstreamOption(IOstreamOption::ASCII, comp),
append,
atomic
)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::ifstreamPointer::open
(
const fileName& pathname,
IOstreamOption streamOpt // Currently unused
)
{
// Forcibly close old stream (if any)
ptr_.reset(nullptr);
const std::ios_base::openmode mode
(
std::ios_base::in | std::ios_base::binary
);
ptr_.reset(new std::ifstream(pathname, mode));
if (!ptr_->good())
{
// Try compressed version instead
const fileName pathname_gz(pathname + ".gz");
if (Foam::isFile(pathname_gz, false))
{
#ifdef HAVE_LIBZ
ptr_.reset(new igzstream(pathname_gz, mode));
#else /* HAVE_LIBZ */
FatalError
<< "No read support for gz compressed files (libz)"
<< " : could use 'gunzip' from the command-line" << nl
<< "file: " << pathname_gz << endl
<< exit(FatalError);
#endif /* HAVE_LIBZ */
}
else
{
// TBD:
// Can also fallback and open .orig files too
//
// auto* file = dynamic_cast<std::ifstream*>(ptr_.get());
// file->open(pathname + ".orig", mode);
}
}
}
void Foam::ifstreamPointer::reopen_gz(const std::string& pathname)
{
#ifdef HAVE_LIBZ
auto* gz = dynamic_cast<igzstream*>(ptr_.get());
if (gz)
{
// Special treatment for gzstream
gz->close();
gz->clear();
gz->open
(
pathname + ".gz",
(std::ios_base::in | std::ios_base::binary)
);
return;
}
#endif /* HAVE_LIBZ */
}
void Foam::ofstreamPointer::reopen(const std::string& pathname)
{
#ifdef HAVE_LIBZ
auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
if (gz)
{
// Special treatment for gzstream
gz->close();
gz->clear();
if (atomic_)
{
gz->open
(
pathname + "~tmp~",
(std::ios_base::out | std::ios_base::binary)
);
}
else
{
gz->open
(
pathname + ".gz",
(std::ios_base::out | std::ios_base::binary)
);
}
return;
}
#endif /* HAVE_LIBZ */
auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
if (file)
{
if (file->is_open())
{
file->close();
}
file->clear();
// Don't need original request to append since rewind implies
// trashing that anyhow.
if (atomic_)
{
file->open
(
pathname + "~tmp~",
(std::ios_base::out | std::ios_base::binary)
);
}
else
{
file->open
(
pathname,
(std::ios_base::out | std::ios_base::binary)
);
}
return;
}
}
void Foam::ofstreamPointer::close(const std::string& pathname)
{
if (!atomic_ || pathname.empty()) return;
#ifdef HAVE_LIBZ
auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
if (gz)
{
// Special treatment for gzstream
gz->close();
gz->clear();
std::rename
(
(pathname + "~tmp~").c_str(),
(pathname + ".gz").c_str()
);
return;
}
#endif /* HAVE_LIBZ */
auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
if (file)
{
if (file->is_open())
{
file->close();
}
file->clear();
std::rename
(
(pathname + "~tmp~").c_str(),
pathname.c_str()
);
return;
}
}
Foam::IOstreamOption::compressionType
Foam::ifstreamPointer::whichCompression() const
{
#ifdef HAVE_LIBZ
if (dynamic_cast<const igzstream*>(ptr_.get()))
{
return IOstreamOption::compressionType::COMPRESSED;
}
#endif /* HAVE_LIBZ */
return IOstreamOption::compressionType::UNCOMPRESSED;
}
Foam::IOstreamOption::compressionType
Foam::ofstreamPointer::whichCompression() const
{
#ifdef HAVE_LIBZ
if (dynamic_cast<const ogzstream*>(ptr_.get()))
{
return IOstreamOption::compressionType::COMPRESSED;
}
#endif /* HAVE_LIBZ */
return IOstreamOption::compressionType::UNCOMPRESSED;
}
// ************************************************************************* //