std::basic_filebuf::open(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– std::basic_filebuf::open πŸ’–

Okay bestie, buckle up β€” this is std::basic_filebuf::open from the C++ Standard Libary (section 3, mwah), and it's literally the function that makes files exist in your program's world. Lowkey iconic. Let's get into it 🫢


🌸 SYNOPSIS 🌸

basic_filebuf* open( const char* s, std::ios_base::openmode mode );
basic_filebuf* open( const std::string& str,
                     std::ios_base::openmode mode );
basic_filebuf* open( const std::filesystem::path& p,
                     std::ios_base::openmode mode );
basic_filebuf* open( const std::filesystem::path::value_type* s,
                     std::ios_base::openmode mode );

The tea on which overload landed when β˜•:

  • (1) β€” the const char* s one, the OG πŸ’…
  • (2) β€” the const std::string& str one, since C++11 ✨
  • (3) β€” the const std::filesystem::path& p one, since C++17 🌈
  • (4) β€” the const std::filesystem::path::value_type* s one, since C++17 πŸ¦‹

πŸ’« DESCRIPTION πŸ’«

First vibe check: if the associated file was already open (is_open() != false), it returns a null pointer right away. No drama, no retry, just nope πŸ™ˆ.

Otherwise, it opens the file with the given name β€” that's s, p.c_str() (since C++17), or str.c_str(), depending on which overload you took. And hey, std::ios_base::openmode values may be written as, e.g., std::ios_base::out | std::ios_base::app β€” OR them together, that's the whole aesthetic πŸ”₯

Real talk: overload (4) is only provided if std::filesystem::path::value_type is not char. (since C++17) Not every platform, not every day. Periodt.

The file is opened as if by calling std::fopen with the second argument (the file access mode) determined by the result of mode & ~std::ios_base::ate as follows β€” and heads up, open() fails if the result is not some combination of flags shown in the table πŸŽ€

The six flag columns are, in order: binary, in, out, trunc, app, noreplace (that last one is since C++23). The dance goes:

When the fopen access mode is "r" β€” action if file already exists: Read from start / if it does not exist: Failure to open

  • - + - - - - β†’ "r"
  • + + - - - - β†’ "rb"

When it's "r+" β€” action if file already exists: Read from start / if it does not exist: Error

  • - + + - - - β†’ "r+"
  • + + + - - - β†’ "r+b"

When it's "w" β€” action if file already exists: Destroy contents / if it does not exist: Create new

  • - - + - - - β†’ "w"
  • - - + + - -
  • + - + - - - β†’ "wb"
  • + - + + - -
  • - + + + - - β†’ "w+"
  • + + + + - - β†’ "w+b"

When it's "wx" β€” action if file already exists: Failure to open / if it does not exist: Create new

  • - - + - - + β†’ "wx"
  • - - + + - +
  • + - + - - + β†’ "wbx"
  • + - + + - +
  • - + + + - + β†’ "w+x"
  • + + + + - + β†’ "w+bx"

When it's "a" β€” action if file already exists: Write to end / if it does not exist: Create new

  • - - + - + - β†’ "a"
  • - - - - + -
  • + - + - + - β†’ "ab"
  • + - - - + -
  • - + + - + - β†’ "a+"
  • - + - - + -
  • + + + - + - β†’ "a+b"
  • + + - - + -

✨ And now the ate moment: if the open operation succeeds and (openmode & std::ios_base::ate) != 0 (the ate bit is set), it repositions the file position to the end of file, as if by calling std::fseek(file, 0, SEEK_END), where file is the pointer returned by calling std::fopen. And if that repositioning fails? It calls close() and returns a null pointer to indicate failure 😭 The audacity, honestly.


πŸŽ€ PARAMETERS πŸŽ€

  • s, str, p β€” the file name to open; s must point to a null-terminated string (no playing around with that one, bestie)
  • openmode β€” the file opening mode, a binary OR of the std::ios_base::openmode modes

✨ RETURN VALUE ✨

this on success, a null pointer on failure. That's it. That's the whole personality πŸ’…


πŸ¦‹ NOTES πŸ¦‹

open() is typically called through the constructor or the open() member function of std::basic_fstream. So like, you'll meet it through a friend, yk? πŸ‘‘


πŸ“ EXAMPLE πŸ“

// Run this code

#include <fstream>
#include <iostream>

int main()
{
    std::string filename = "Test.b";
    std::filebuf fb;

    // prepare a file to read
    double d = 3.14;
    if (!fb.open(filename, std::ios::binary | std::ios::out))
    {
        std::cout << "Open file " << filename << " for write failed\n";
        return 1;
    }
    fb.sputn(reinterpret_cast<char*>(&d), sizeof d);
    fb.close();

    // open file for reading
    double d2 = 0.0;
    if (!fb.open(filename, std::ios::binary | std::ios::in))
    {
        std::cout << "Open file " << filename << " for read failed\n";
        return 1;
    }

    auto got = fb.sgetn(reinterpret_cast<char*>(&d2), sizeof d2);
    if (sizeof(d2) != got)
        std::cout << "Read of " << filename << " failed\n";
    else
        std::cout << "Read back from file: " << d2 << '\n';
}

Output:

Read back from file: 3.14

She wrote it, she read it back, she ate. No crumbs. 🍽️✨


πŸ’… DEFECT REPORTS πŸ’…

The following behavior-changing defect reports were applied retroactively to previously published C++ standards β€” yes, they went back and fixed the lore πŸ™ˆ

  • LWG 596 β€” Applied to C++98 β€” behavior as published: open() could not open files in append mode. Correct behavior: can open in append mode. Glow-up of the century, honestly πŸ”₯

πŸ”₯ SEE ALSO πŸ”₯

  • is_open β€” checks if the associated file is open (public member function) πŸ‘€
  • close β€” flushes the put area buffer and closes the associated file (public member function) πŸšͺ

Okay that's the whole page, bestie! Sourced straight from cppreference.com and dated 2024.06.10, and yeah, the page is std::basic_filebuf::open(3) β€” go open some files, but, like, responsibly πŸ’–πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from