ENH: improve OFstream append behaviour (#3160)
- previous support for file appending (largely unused) always specified opening with the std::ios_base::app flag. Now differentiate between append behaviours: APPEND_APP ~~~~~~~~~~ Corresponds to std::ios_base::app behaviour: - Existing files will be preserved and a seek-to-end is performed at every write. With this mode seeks/repositioning within the file will effectively be ignored on output. APPEND_ATE ~~~~~~~~~~ Largely approximates std::ios_base::ate behaviour: - Existing files will be preserved and a seek-to-end is performed immediately after opening, but not subsequently. Can use seekp() to overwrite parts of a file.
This commit is contained in:
parent
9f032057b4
commit
ee895577ae
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
Copyright (C) 2022-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -32,10 +32,14 @@ Description
|
||||
#include "IOstreams.H"
|
||||
#include "OSspecific.H"
|
||||
#include "argList.H"
|
||||
#include "clock.H"
|
||||
#include "Switch.H"
|
||||
#include "ListOps.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
std::string time_stamp;
|
||||
|
||||
void listFiles(const fileName& dir)
|
||||
{
|
||||
wordList files = ListOps::create<word>
|
||||
@ -55,25 +59,150 @@ void listFiles(const fileName& dir)
|
||||
}
|
||||
|
||||
|
||||
OSstream& printInfo(OFstream& os)
|
||||
{
|
||||
InfoErr
|
||||
<< "open: " << os.name() << nl
|
||||
<< "appending: " << Switch::name(os.is_appending())
|
||||
<< " tellp: "<< os.stdStream().tellp()
|
||||
<< " gz: " << Switch::name(os.compression()) << nl;
|
||||
|
||||
return InfoErr.stream();
|
||||
}
|
||||
|
||||
|
||||
void withHeader(OFstream& os)
|
||||
{
|
||||
const auto tellp = os.stdStream().tellp();
|
||||
|
||||
if (tellp <= 0)
|
||||
{
|
||||
InfoErr
|
||||
<< "Add header" << nl;
|
||||
os << "HEADER: " << time_stamp.c_str() << nl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class OSstreamType>
|
||||
void generateLines(OSstreamType& os, label count = 1)
|
||||
{
|
||||
for (label line = 1; line <= count; ++line)
|
||||
{
|
||||
os << "[" << line
|
||||
<< "] =============================================" << nl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class OSstreamType>
|
||||
void generateContent
|
||||
(
|
||||
OSstreamType& os,
|
||||
const bool with_seekend,
|
||||
const bool test_overwrite = false,
|
||||
const int64_t seek_out = -1
|
||||
)
|
||||
{
|
||||
if (with_seekend)
|
||||
{
|
||||
os.stdStream().seekp(0, std::ios_base::end);
|
||||
// OR? os.seek_end();
|
||||
}
|
||||
|
||||
printInfo(os);
|
||||
|
||||
withHeader(os);
|
||||
|
||||
if (test_overwrite && seek_out >= 0)
|
||||
{
|
||||
InfoErr<< "... seekp(" << seek_out << ")" << nl;
|
||||
|
||||
auto& oss = os.stdStream();
|
||||
|
||||
// Actually std::streampos, but cannot increment that
|
||||
|
||||
int64_t pos(seek_out);
|
||||
|
||||
const int64_t tellp_end = oss.tellp();
|
||||
|
||||
if (pos >= 0 && pos < tellp_end)
|
||||
{
|
||||
InfoErr
|
||||
<< "... fill from " << label(pos)
|
||||
<< " to " << label(tellp_end) << nl;
|
||||
|
||||
oss.seekp(pos);
|
||||
|
||||
while (pos < tellp_end)
|
||||
{
|
||||
// Fill with char 'X', rely on streambuf buffering
|
||||
oss << 'X';
|
||||
++pos;
|
||||
}
|
||||
|
||||
oss.seekp(seek_out);
|
||||
os << "More content [at " << seek_out << ']' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
generateLines(os, 4);
|
||||
|
||||
printInfo(os)
|
||||
<< "... sleep" << endl;
|
||||
|
||||
listFiles(os.name().path());
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "[new content] +++++++++++++++++++++++++++++++++++" << endl;
|
||||
}
|
||||
|
||||
|
||||
template<class OSstreamType>
|
||||
void generateOverwriteContent
|
||||
(
|
||||
OSstreamType& os,
|
||||
const bool with_seekend,
|
||||
const int64_t seek_out = -1
|
||||
)
|
||||
{
|
||||
generateContent(os, with_seekend, true, seek_out);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Main program:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addBoolOption("gz", "Use compression");
|
||||
argList::addBoolOption("append", "Use append mode");
|
||||
argList::addBoolOption("append-app", "Use append app mode");
|
||||
argList::addBoolOption("append-ate", "Use append ate mode");
|
||||
argList::addBoolOption("seekend", "Seek to end after non-append open");
|
||||
argList::addOption("seek", "value", "Seek from start (default: 100)");
|
||||
argList::addBoolOption("atomic", "Use atomic");
|
||||
argList::addBoolOption("keep", "Do not remove test directory");
|
||||
argList::addOption("write", "file", "test writing to file");
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
// Same time-stamp for all generated files
|
||||
time_stamp = clock::dateTime();
|
||||
|
||||
const fileName baseDir("Test-OFstream-directory");
|
||||
|
||||
Foam::mkDir(baseDir);
|
||||
|
||||
InfoErr<< "mkdir: " << baseDir << endl;
|
||||
|
||||
Info<< "start:" << nl;
|
||||
listFiles(baseDir);
|
||||
|
||||
const bool with_seekend = args.found("seekend");
|
||||
|
||||
const int seek_out = args.getOrDefault<int>("seek", 100);
|
||||
|
||||
IOstreamOption streamOpt;
|
||||
|
||||
if (args.found("gz"))
|
||||
@ -83,10 +212,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
IOstreamOption::appendType append =
|
||||
(
|
||||
args.found("append")
|
||||
? IOstreamOption::APPEND
|
||||
: IOstreamOption::NON_APPEND
|
||||
args.found("append-app") ? IOstreamOption::APPEND_APP
|
||||
: args.found("append-ate") ? IOstreamOption::APPEND_ATE
|
||||
: IOstreamOption::NO_APPEND
|
||||
);
|
||||
|
||||
IOstreamOption::atomicType atomic =
|
||||
(
|
||||
args.found("atomic")
|
||||
@ -97,7 +227,6 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
OFstream(baseDir/"dummy")() << "Some file content" << endl;
|
||||
|
||||
Foam::ln("dummy", baseDir/"Test2.txt");
|
||||
Foam::ln("dummy", baseDir/"Test3.txt");
|
||||
Foam::ln("dummy", baseDir/"Test4.txt");
|
||||
Foam::ln("dummy", baseDir/"Test4.txt.gz");
|
||||
@ -114,16 +243,31 @@ int main(int argc, char *argv[])
|
||||
append
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
generateOverwriteContent(os, with_seekend, seek_out);
|
||||
}
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
atomic,
|
||||
baseDir/"Test1-app.txt",
|
||||
streamOpt,
|
||||
IOstreamOption::APPEND_APP
|
||||
);
|
||||
|
||||
listFiles(baseDir);
|
||||
generateOverwriteContent(os, with_seekend, seek_out);
|
||||
}
|
||||
|
||||
sleep(2);
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
atomic,
|
||||
baseDir/"Test1-ate.txt",
|
||||
streamOpt,
|
||||
IOstreamOption::APPEND_ATE
|
||||
);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
generateOverwriteContent(os, with_seekend, seek_out);
|
||||
}
|
||||
|
||||
{
|
||||
@ -132,39 +276,21 @@ int main(int argc, char *argv[])
|
||||
atomic,
|
||||
baseDir/"Test2.txt",
|
||||
streamOpt
|
||||
// NON_APPEND
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
generateContent(os, with_seekend);
|
||||
}
|
||||
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
atomic,
|
||||
baseDir/"Test3.txt",
|
||||
streamOpt,
|
||||
IOstreamOption::APPEND
|
||||
IOstreamOption::APPEND_APP
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
generateContent(os, with_seekend, with_seekend);
|
||||
}
|
||||
{
|
||||
OFstream os
|
||||
@ -174,35 +300,17 @@ int main(int argc, char *argv[])
|
||||
IOstreamOption::COMPRESSED
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
// No seekend with COMPRESSED
|
||||
generateContent(os, false);
|
||||
}
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
IOstreamOption::ATOMIC,
|
||||
baseDir/"Test5.txt"
|
||||
// ASCII UNCOMPRESSED NON_APPEND
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
generateContent(os, with_seekend);
|
||||
}
|
||||
|
||||
Info<< nl << "done:" << endl;
|
||||
|
@ -28,7 +28,8 @@ Class
|
||||
Foam::IFstream
|
||||
|
||||
Description
|
||||
Input from file stream, using an ISstream
|
||||
Input from file stream as an ISstream, normally using \c std::ifstream
|
||||
for the actual input.
|
||||
|
||||
SourceFiles
|
||||
IFstream.C
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2017 OpenFOAM Foundation
|
||||
Copyright (C) 2017-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2017-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -66,7 +66,7 @@ Foam::OFstream::OFstream
|
||||
(
|
||||
pathname,
|
||||
streamOpt,
|
||||
(IOstreamOption::appendType::APPEND == append),
|
||||
append,
|
||||
(IOstreamOption::atomicType::ATOMIC == atomic)
|
||||
),
|
||||
OSstream(*(ofstreamPointer::get()), pathname, streamOpt)
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2017 OpenFOAM Foundation
|
||||
Copyright (C) 2017-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2017-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -28,7 +28,29 @@ Class
|
||||
Foam::OFstream
|
||||
|
||||
Description
|
||||
Output to file stream, using an OSstream
|
||||
Output to file stream as an OSstream, normally using \c std::ofstream
|
||||
for the actual output.
|
||||
|
||||
Note
|
||||
The atomic output works by creating an intermediate temporary file,
|
||||
which is renamed as an atomic operation when closing. It is not
|
||||
possible, or particularly desirable, to have an atomic in combination
|
||||
with append behaviour. If both are specified, append has priority.
|
||||
|
||||
Note
|
||||
An output file can be opened in two different \c append modes, both of
|
||||
which preserve existing files:
|
||||
-# A common append mode is APPEND_APP, which corresponds to the
|
||||
\c std::ios_base::app flag.
|
||||
A seek-to-end is performed at \em every write.
|
||||
It is thus not possible to use any manual seeks to overwrite parts
|
||||
of the file.
|
||||
-# The other append mode is APPEND_ATE, which roughly corresponds to the
|
||||
\c std::ios_base::ate flag behaviour.
|
||||
A seek-to-end is performed immediately after opening,
|
||||
but not subsequently.
|
||||
Manual seeks can be used to overwrite parts of the file.
|
||||
.
|
||||
|
||||
SourceFiles
|
||||
OFstream.C
|
||||
@ -64,53 +86,55 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct a null output file stream.
|
||||
// Behaves like \c /dev/null and is named accordingly
|
||||
//- Construct a null output file stream that behaves like \c /dev/null
|
||||
explicit OFstream(std::nullptr_t);
|
||||
|
||||
//- Construct with specified atomic behaviour
|
||||
//- from pathname, stream option, optional append
|
||||
//- from pathname, stream option, optional append (see note).
|
||||
OFstream
|
||||
(
|
||||
IOstreamOption::atomicType atomic,
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND
|
||||
);
|
||||
|
||||
//- Construct from pathname and other specifications
|
||||
//- Construct from pathname and other specifications.
|
||||
// See note on append mode.
|
||||
explicit OFstream
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND
|
||||
)
|
||||
:
|
||||
OFstream(IOstreamOption::NON_ATOMIC, pathname, streamOpt, append)
|
||||
{}
|
||||
|
||||
//- Construct from pathname, format (uncompressed), optional append,
|
||||
//- Construct from pathname, format (uncompressed),
|
||||
//- optional append (see note),
|
||||
//- atomic behaviour as per system default
|
||||
OFstream
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt,
|
||||
IOstreamOption::compressionType cmp = IOstreamOption::UNCOMPRESSED,
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND
|
||||
)
|
||||
:
|
||||
OFstream(pathname, IOstreamOption(fmt, cmp), append)
|
||||
{}
|
||||
|
||||
//- Construct with specified atomic behaviour
|
||||
//- from pathname, format (uncompressed), optional append
|
||||
//- from pathname, format (uncompressed),
|
||||
//- optional append (see note).
|
||||
OFstream
|
||||
(
|
||||
IOstreamOption::atomicType atomic,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt,
|
||||
IOstreamOption::compressionType cmp = IOstreamOption::UNCOMPRESSED,
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND
|
||||
)
|
||||
:
|
||||
OFstream(atomic, pathname, IOstreamOption(fmt, cmp), append)
|
||||
@ -141,6 +165,21 @@ public:
|
||||
virtual void rewind();
|
||||
|
||||
|
||||
// Output stream modes
|
||||
|
||||
//- True if opened in append mode \em and file already existed
|
||||
bool is_appending() const noexcept
|
||||
{
|
||||
return ofstreamPointer::is_appending();
|
||||
}
|
||||
|
||||
//- True if file creation behaves as atomic
|
||||
bool is_atomic() const noexcept
|
||||
{
|
||||
return ofstreamPointer::is_atomic();
|
||||
}
|
||||
|
||||
|
||||
// Print
|
||||
|
||||
//- Print stream description
|
||||
@ -158,7 +197,7 @@ public:
|
||||
IOstreamOption::streamFormat fmt,
|
||||
IOstreamOption::versionNumber ver,
|
||||
IOstreamOption::compressionType cmp = IOstreamOption::UNCOMPRESSED,
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND
|
||||
)
|
||||
:
|
||||
OFstream(pathname, IOstreamOption(fmt, ver, cmp), append)
|
||||
|
@ -194,20 +194,37 @@ public:
|
||||
|
||||
class ofstreamPointer
|
||||
{
|
||||
// Private Data Types
|
||||
|
||||
//- The file open/creation type (bitmask)
|
||||
enum modeType : char
|
||||
{
|
||||
NONE = 0, // Regular open (truncates existing)
|
||||
ATOMIC = 0x1, // Atomic file creation
|
||||
APPENDING = 0x2 // Is appending to an existing file
|
||||
};
|
||||
|
||||
|
||||
// Private Data
|
||||
|
||||
//- The stream pointer (ofstream | ogzstream | ocountstream, ...)
|
||||
std::unique_ptr<std::ostream> ptr_;
|
||||
|
||||
//- Atomic file creation
|
||||
bool atomic_;
|
||||
//- File output/creation type (atomic, append etc)
|
||||
char mode_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Clear any output mode information
|
||||
void clear_mode() noexcept { mode_ = modeType::NONE; }
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Reopen for compressed/non-compressed
|
||||
//- Reopen for compressed/non-compressed. Discards append status.
|
||||
void reopen(const std::string& pathname);
|
||||
|
||||
//- Close stream and rename file
|
||||
@ -245,16 +262,20 @@ public:
|
||||
//- Construct from pathname, option, append, file handling atomic
|
||||
// \param pathname The file name to open for writing
|
||||
// \param streamOpt Respects (UNCOMPRESSED | COMPRESSED)
|
||||
// \param append Open in append mode
|
||||
// \param append Open in specified append mode
|
||||
// \param atomic Write into temporary file (not target file).
|
||||
// This option should only be used with a stream wrapper
|
||||
// (eg, OFstream) that handles the final renaming.
|
||||
//
|
||||
// \note
|
||||
// There are two different append modes:
|
||||
// append at every write, or only append after opening.
|
||||
explicit ofstreamPointer
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
const bool append = false,
|
||||
const bool atomic = false
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND,
|
||||
bool atomic = false
|
||||
);
|
||||
|
||||
//- Construct from pathname, compression, append, file handling atomic
|
||||
@ -268,12 +289,12 @@ public:
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::compressionType comp,
|
||||
const bool append = false,
|
||||
const bool atomic = false
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND,
|
||||
bool atomic = false
|
||||
);
|
||||
|
||||
|
||||
// Member Functions
|
||||
// Static Functions
|
||||
|
||||
//- True if compiled with libz support
|
||||
static bool supports_gz() noexcept;
|
||||
@ -293,14 +314,34 @@ public:
|
||||
//- Which compression type?
|
||||
IOstreamOption::compressionType whichCompression() const;
|
||||
|
||||
//- True if opened in append mode \em and file already existed
|
||||
bool is_appending() const noexcept
|
||||
{
|
||||
return (mode_ & modeType::APPENDING);
|
||||
}
|
||||
|
||||
//- True if file creation behaves as atomic
|
||||
bool is_atomic() const noexcept
|
||||
{
|
||||
return (mode_ & modeType::ATOMIC);
|
||||
}
|
||||
|
||||
|
||||
// Edit
|
||||
|
||||
//- Return managed pointer and release ownership
|
||||
std::ostream* release() noexcept { return ptr_.release(); }
|
||||
//- Return managed pointer and release ownership.
|
||||
std::ostream* release() noexcept
|
||||
{
|
||||
clear_mode();
|
||||
return ptr_.release();
|
||||
}
|
||||
|
||||
//- Replace the managed pointer
|
||||
void reset(std::ostream* ptr) noexcept { ptr_.reset(ptr); }
|
||||
void reset(std::ostream* ptr) noexcept
|
||||
{
|
||||
clear_mode();
|
||||
ptr_.reset(ptr);
|
||||
}
|
||||
|
||||
|
||||
// Operators
|
||||
|
@ -88,14 +88,14 @@ Foam::ifstreamPointer::ifstreamPointer
|
||||
Foam::ofstreamPointer::ofstreamPointer() noexcept
|
||||
:
|
||||
ptr_(),
|
||||
atomic_(false)
|
||||
mode_(modeType::NONE)
|
||||
{}
|
||||
|
||||
|
||||
Foam::ofstreamPointer::ofstreamPointer(std::nullptr_t)
|
||||
:
|
||||
ptr_(new Foam::ocountstream),
|
||||
atomic_(false)
|
||||
mode_(modeType::NONE)
|
||||
{}
|
||||
|
||||
|
||||
@ -103,27 +103,44 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt,
|
||||
const bool append,
|
||||
const bool atomic
|
||||
IOstreamOption::appendType append,
|
||||
bool atomic
|
||||
)
|
||||
:
|
||||
ptr_(),
|
||||
atomic_(atomic)
|
||||
mode_(modeType::NONE)
|
||||
{
|
||||
std::ios_base::openmode mode
|
||||
// Leave std::ios_base::trunc implicitly handled to make things
|
||||
// easier for append mode.
|
||||
|
||||
std::ios_base::openmode openmode
|
||||
(
|
||||
std::ios_base::out | std::ios_base::binary
|
||||
);
|
||||
|
||||
if (append)
|
||||
if (append == IOstreamOption::APPEND_APP)
|
||||
{
|
||||
mode |= std::ios_base::app;
|
||||
openmode |= std::ios_base::app;
|
||||
|
||||
// Cannot append to gzstream
|
||||
streamOpt.compression(IOstreamOption::UNCOMPRESSED);
|
||||
|
||||
// Cannot use append + atomic operation, without lots of extra work
|
||||
atomic_ = false;
|
||||
atomic = false;
|
||||
}
|
||||
else if (append == IOstreamOption::APPEND_ATE)
|
||||
{
|
||||
// Handle an "append-like" mode by opening "r+b" and NOT as "ab"
|
||||
// - file already exists: Sets read position to start
|
||||
// - file does not exist: Error
|
||||
|
||||
openmode |= std::ios_base::in; // [SIC] - use read bit, not append!
|
||||
|
||||
// Cannot append to gzstream
|
||||
streamOpt.compression(IOstreamOption::UNCOMPRESSED);
|
||||
|
||||
// Cannot use append + atomic operation, without lots of extra work
|
||||
atomic = false;
|
||||
}
|
||||
|
||||
|
||||
@ -146,9 +163,9 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
// TBD:
|
||||
// atomic_ = true; // Always treat COMPRESSED like an atomic
|
||||
// atomic = true; // Always treat COMPRESSED like an atomic
|
||||
|
||||
const fileName& target = (atomic_ ? pathname_tmp : pathname_gz);
|
||||
const fileName& target = (atomic ? pathname_tmp : pathname_gz);
|
||||
|
||||
// Remove old uncompressed version (if any)
|
||||
fType = Foam::type(pathname, false);
|
||||
@ -158,7 +175,7 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
}
|
||||
|
||||
// Avoid writing into symlinked files (non-append mode)
|
||||
if (!append || atomic_)
|
||||
if (atomic || (append == IOstreamOption::NO_APPEND))
|
||||
{
|
||||
fType = Foam::type(target, false);
|
||||
if (fType == fileName::SYMLINK)
|
||||
@ -167,7 +184,7 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
}
|
||||
}
|
||||
|
||||
ptr_.reset(new ogzstream(target, mode));
|
||||
ptr_.reset(new ogzstream(target, openmode));
|
||||
|
||||
#else /* HAVE_LIBZ */
|
||||
|
||||
@ -184,7 +201,7 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
|
||||
if (IOstreamOption::COMPRESSED != streamOpt.compression())
|
||||
{
|
||||
const fileName& target = (atomic_ ? pathname_tmp : pathname);
|
||||
const fileName& target = (atomic ? pathname_tmp : pathname);
|
||||
|
||||
// Remove old compressed version (if any)
|
||||
fType = Foam::type(pathname_gz, false);
|
||||
@ -194,7 +211,7 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
}
|
||||
|
||||
// Avoid writing into symlinked files (non-append mode)
|
||||
if (!append || atomic_)
|
||||
if (atomic || (append == IOstreamOption::NO_APPEND))
|
||||
{
|
||||
fType = Foam::type(target, false);
|
||||
if (fType == fileName::SYMLINK)
|
||||
@ -203,7 +220,75 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
}
|
||||
}
|
||||
|
||||
ptr_.reset(new std::ofstream(target, mode));
|
||||
// File pointer (std::ofstream)
|
||||
auto filePtr = std::make_unique<std::ofstream>(target, openmode);
|
||||
|
||||
if (append == IOstreamOption::APPEND_APP)
|
||||
{
|
||||
// Final handling for append 'app' (always non-atomic)
|
||||
|
||||
// Set output position to the end (like std::ios_base::ate)
|
||||
// but only to test if the file had a size.
|
||||
// No real performance problem since any subsequent write
|
||||
// will do the same anyhow.
|
||||
|
||||
filePtr->seekp(0, std::ios_base::end);
|
||||
if (filePtr->tellp() <= 0)
|
||||
{
|
||||
// Did not open an existing file
|
||||
append = IOstreamOption::NO_APPEND;
|
||||
}
|
||||
}
|
||||
else if (append == IOstreamOption::APPEND_ATE)
|
||||
{
|
||||
// Final handling for append 'ate' (always non-atomic)
|
||||
|
||||
if (filePtr->good())
|
||||
{
|
||||
// Success if file already exists.
|
||||
// Set output position to the end - like std::ios_base::ate
|
||||
|
||||
filePtr->seekp(0, std::ios_base::end);
|
||||
|
||||
if (filePtr->tellp() <= 0)
|
||||
{
|
||||
// Did not open an existing file
|
||||
append = IOstreamOption::NO_APPEND;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error if file does not already exist.
|
||||
// Reopen as regular output mode only.
|
||||
|
||||
// Did not open an existing file
|
||||
append = IOstreamOption::NO_APPEND;
|
||||
|
||||
if (filePtr->is_open())
|
||||
{
|
||||
filePtr->close();
|
||||
}
|
||||
filePtr->clear();
|
||||
filePtr->open
|
||||
(
|
||||
target,
|
||||
(std::ios_base::out | std::ios_base::binary)
|
||||
);
|
||||
}
|
||||
}
|
||||
ptr_.reset(filePtr.release());
|
||||
}
|
||||
|
||||
// Is appending to an existing file
|
||||
if (append != IOstreamOption::NO_APPEND)
|
||||
{
|
||||
mode_ = modeType::APPENDING;
|
||||
}
|
||||
|
||||
// An atomic output operation (normally not appending!)
|
||||
if (atomic)
|
||||
{
|
||||
mode_ |= modeType::ATOMIC;
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,8 +297,8 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::compressionType comp,
|
||||
const bool append,
|
||||
const bool atomic
|
||||
IOstreamOption::appendType append,
|
||||
bool atomic
|
||||
)
|
||||
:
|
||||
ofstreamPointer
|
||||
@ -237,12 +322,12 @@ void Foam::ifstreamPointer::open
|
||||
// Forcibly close old stream (if any)
|
||||
ptr_.reset(nullptr);
|
||||
|
||||
const std::ios_base::openmode mode
|
||||
const std::ios_base::openmode openmode
|
||||
(
|
||||
std::ios_base::in | std::ios_base::binary
|
||||
);
|
||||
|
||||
ptr_.reset(new std::ifstream(pathname, mode));
|
||||
ptr_.reset(new std::ifstream(pathname, openmode));
|
||||
|
||||
if (!ptr_->good())
|
||||
{
|
||||
@ -254,7 +339,7 @@ void Foam::ifstreamPointer::open
|
||||
{
|
||||
#ifdef HAVE_LIBZ
|
||||
|
||||
ptr_.reset(new igzstream(pathname_gz, mode));
|
||||
ptr_.reset(new igzstream(pathname_gz, openmode));
|
||||
|
||||
#else /* HAVE_LIBZ */
|
||||
|
||||
@ -311,7 +396,7 @@ void Foam::ofstreamPointer::reopen(const std::string& pathname)
|
||||
gz->close();
|
||||
gz->clear();
|
||||
|
||||
if (atomic_)
|
||||
if (mode_ & modeType::ATOMIC)
|
||||
{
|
||||
gz->open
|
||||
(
|
||||
@ -341,10 +426,11 @@ void Foam::ofstreamPointer::reopen(const std::string& pathname)
|
||||
}
|
||||
file->clear();
|
||||
|
||||
// Don't need original request to append since rewind implies
|
||||
// trashing that anyhow.
|
||||
// Invalidate the appending into existing file information
|
||||
// since rewind usually means overwrite
|
||||
mode_ &= ~modeType::APPENDING;
|
||||
|
||||
if (atomic_)
|
||||
if (mode_ & modeType::ATOMIC)
|
||||
{
|
||||
file->open
|
||||
(
|
||||
@ -367,7 +453,13 @@ void Foam::ofstreamPointer::reopen(const std::string& pathname)
|
||||
|
||||
void Foam::ofstreamPointer::close(const std::string& pathname)
|
||||
{
|
||||
if (!atomic_ || pathname.empty()) return;
|
||||
// Invalidate the appending into existing file information
|
||||
mode_ &= ~modeType::APPENDING;
|
||||
|
||||
if (pathname.empty() || !(mode_ & modeType::ATOMIC))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
|
||||
|
@ -107,7 +107,7 @@ public:
|
||||
const label comm,
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND,
|
||||
const bool writeOnProc = true
|
||||
);
|
||||
|
||||
@ -118,7 +118,7 @@ public:
|
||||
const label comm,
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND,
|
||||
const bool writeOnProc = true
|
||||
)
|
||||
:
|
||||
@ -140,7 +140,7 @@ public:
|
||||
IOstreamOption::atomicType atomic,
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND,
|
||||
const bool writeOnProc = true
|
||||
)
|
||||
:
|
||||
@ -161,7 +161,7 @@ public:
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::appendType append = IOstreamOption::NO_APPEND,
|
||||
const bool writeOnProc = true
|
||||
)
|
||||
:
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2015 OpenFOAM Foundation
|
||||
Copyright (C) 2018-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -36,9 +36,6 @@ Description
|
||||
The compression (UNCOMPRESSED | COMPRESSED) is typically controlled
|
||||
by switch values (true/false, on/off, ...).
|
||||
|
||||
Additionally, some enumerations are defined (APPEND, NON_APPEND, ...)
|
||||
that are useful, verbose alternatives to bool values.
|
||||
|
||||
SourceFiles
|
||||
IOstreamOption.C
|
||||
|
||||
@ -84,11 +81,14 @@ public:
|
||||
COMPRESSED //!< compression = true
|
||||
};
|
||||
|
||||
//- File appending (NON_APPEND | APPEND)
|
||||
//- File appending (NO_APPEND | APPEND_APP | APPEND_ATE)
|
||||
enum appendType : char
|
||||
{
|
||||
NON_APPEND = 0, //!< append = false
|
||||
APPEND //!< append = true
|
||||
NO_APPEND = 0, //!< no append (truncates existing)
|
||||
APPEND_APP, //!< append (seek end each write)
|
||||
APPEND_ATE, //!< append (seek end after open)
|
||||
NON_APPEND = NO_APPEND, //!< old name for NO_APPEND
|
||||
APPEND = APPEND_APP //!< old name for APPEND_APP
|
||||
};
|
||||
|
||||
//- Atomic operations (output)
|
||||
|
@ -80,7 +80,7 @@ bool Foam::OFstreamCollator::writeFile
|
||||
osPtr.reset(new OFstream(atomic, fName, streamOpt, append));
|
||||
auto& os = *osPtr;
|
||||
|
||||
if (append == IOstreamOption::NON_APPEND)
|
||||
if (append == IOstreamOption::NO_APPEND)
|
||||
{
|
||||
// No IOobject so cannot use IOobject::writeHeader
|
||||
|
||||
|
@ -190,7 +190,7 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
|
||||
// UNCOMPRESSED (binary only)
|
||||
IOstreamOption(IOstreamOption::BINARY, streamOpt.version()),
|
||||
// Append on sub-ranks
|
||||
(isIOmaster ? IOstreamOption::NON_APPEND : IOstreamOption::APPEND)
|
||||
(isIOmaster ? IOstreamOption::NO_APPEND : IOstreamOption::APPEND_APP)
|
||||
);
|
||||
|
||||
if (!os.good())
|
||||
@ -384,7 +384,7 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
|
||||
comm_,
|
||||
pathName,
|
||||
streamOpt,
|
||||
IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::NO_APPEND,
|
||||
writeOnProc
|
||||
);
|
||||
|
||||
@ -431,7 +431,7 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
|
||||
comm_,
|
||||
pathName,
|
||||
streamOpt,
|
||||
IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::NO_APPEND,
|
||||
writeOnProc
|
||||
);
|
||||
|
||||
|
@ -81,7 +81,7 @@ Foam::threadedCollatedOFstream::~threadedCollatedOFstream()
|
||||
str(),
|
||||
IOstreamOption(IOstreamOption::BINARY, version(), compression_),
|
||||
atomic_,
|
||||
IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::NO_APPEND,
|
||||
useThread_,
|
||||
headerEntries_
|
||||
);
|
||||
|
@ -2505,7 +2505,7 @@ Foam::fileOperations::masterUncollatedFileOperation::NewOFstream
|
||||
comm_,
|
||||
pathName,
|
||||
streamOpt,
|
||||
IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::NO_APPEND,
|
||||
writeOnProc
|
||||
)
|
||||
);
|
||||
@ -2529,7 +2529,7 @@ Foam::fileOperations::masterUncollatedFileOperation::NewOFstream
|
||||
comm_,
|
||||
pathName,
|
||||
streamOpt,
|
||||
IOstreamOption::NON_APPEND,
|
||||
IOstreamOption::NO_APPEND,
|
||||
writeOnProc
|
||||
)
|
||||
);
|
||||
|
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -1291,7 +1291,7 @@ bool Foam::lumpedPointMovement::writeData
|
||||
const Tuple2<scalar, scalar>* timesWritten
|
||||
) const
|
||||
{
|
||||
if (!Pstream::master())
|
||||
if (!UPstream::master())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1306,13 +1306,13 @@ bool Foam::lumpedPointMovement::writeData
|
||||
writeData(os, forces, moments, outputFormat_, timesWritten);
|
||||
}
|
||||
|
||||
// Log output
|
||||
// Log output - simple append to existing
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
coupler().resolveFile(logName_),
|
||||
IOstreamOption(),
|
||||
IOstreamOption::APPEND
|
||||
IOstreamOption::APPEND_ATE
|
||||
);
|
||||
|
||||
writeData(os, forces, moments, outputFormatType::PLAIN, timesWritten);
|
||||
|
Loading…
Reference in New Issue
Block a user