wchar_t file streams
The std::wfstream is similar to std::fstream except it accepts wchar_t. However it does not write std::wchar_t characters to file. Suppose the following code:
std::wofstream ofs;
ofs.open(L"c:\\temp\\1.txt" , std::ios_base::out | std::ios_base::binary) ;
ofs.write(L"ABC", 3);
On the Windows platform this writes just single bytes characters to the file. The reason is that the locale bound to the file stream translates wchar_t to char. This can be fixed by using a custom locale which doesn't do this. This translation is quite unexpected behavior since the function prototypes are defined in terms of wchar_t. It is also different compared to the wchar_t string streams: std::wstringstream does write wchar_t strings unaffected.
This page was inspired by a YouTube comment of me where I stated that the C FILE api is less surprising. Of course there is always a clown who thinks better but probably doesn't know anything about above issue. With C stream I/O FILE and 'fwrite' the bytes are transferred to the file without interpretation and alteration.
FILE wrapper
Jason Turner goes a lengthy way of wrapping the C FILE api but using a wrapper class would probably be simpler:
class c_file
{
public:
c_file()
: m_fp(nullptr)
{
}
explicit c_file(const std::filesystem::path& rpth, const char* pszMode)
: m_fp(fopen(rpth.string().c_str(), pszMode))
{
}
~c_file()
{
if (m_fp)
{
fclose(m_fp);
}
}
c_file(const c_file&) = delete;
c_file(c_file&& rOther) noexcept
: m_fp(std::exchange(rOther.m_fp, nullptr))
{
}
c_file& operator=(const c_file&) = delete;
c_file& operator=(c_file&& rOther) noexcept
{
std::swap(m_fp, rOther.m_fp);
}
explicit operator bool() const
{
return m_fp;
}
size_t read(void* pBuffer, size_t size, size_t count)
{
return fread(pBuffer, size, count, m_fp);
}
size_t write(const void* pBuffer, size_t size, size_t count)
{
return fwrite(pBuffer, size, count, m_fp);
}
// etc.
private:
FILE* m_fp;
};