Wrote to a file using std::wofstream. The file remained empty - c++

I wrote the following program using VS2008:
#include <fstream>
int main()
{
std::wofstream fout("myfile");
fout << L"Հայաստան Россия Österreich Ελλάδα भारत" << std::endl;
}
When I tried to compile it the IDE asked me whether I wanted to save my source file in unicode, I said "yes, please".
Then I run the program, and myfile appeared in my project's folder. I opened it with notepad, the file was empty. I recalled that notepad supported only ASCII data. I opened it with WordPad, it was still empty. Finally the little genius inside me urged me to look at the file size and not surprisingly it was 0 bytes. So I rebuilt and reran the program, to no effect. Finally I decided to ask very intelligent people on StackOverflow as to what I am missing and here I am :)
Edited:
After the abovementioned intelligent people left some comments, I decided to follow their advice and rewrote the program like this:
#include <fstream>
#include <iostream>
int main()
{
std::wofstream fout("myfile");
if(!fout.is_open())
{
std::cout << "Before: Not open...\n";
}
fout << L"Հայաստան Россия Österreich Ελλάδα भारत" << std::endl;
if(!fout.good())
{
std::cout << "After: Not good...\n";
}
}
Built it. Ran it. And... the console clearly read, to my surprise: "After: Not good...".
So I edited my post to provide the new information and started waiting for answers which would explain why this is and what I could do. :)

MSVC offers the codecvt_utf8 locale facet for this problem.
#include <codecvt>
// ...
std::wofstream fout(fileName);
std::locale loc(std::locale::classic(), new std::codecvt_utf8<wchar_t>);
fout.imbue(loc);

In Visual studio the output stream is always written in ANSI encoding, and it does not support UTF-8 output.
What is basically need to do is to create a locale class, install into it UTF-8 facet and then imbue it to the fstream.
What happens that code points are not being converted to UTF encoding. So basically this would not work under MSVC as it does not support UTF-8.
This would work under Linux with UTF-8 locale
#include <fstream>
int main()
{
std::locale::global(std::locale(""));
std::wofstream fout("myfile");
fout << L"Հայաստան Россия Österreich Ελλάδα भारत" << std::endl;
}
~
And under windows this would work:
#include <fstream>
int main()
{
std::locale::global(std::locale("Russian_Russia"));
std::wofstream fout("myfile");
fout << L"Россия" << std::endl;
}
As only ANSI encodings are supported by MSVC.
Codecvt facet can be found in some Boost libraries. For example: http://www.boost.org/doc/libs/1_38_0/libs/serialization/doc/codecvt.html

I found the following code working properly. I am using VS2019.
#include <iostream>
#include <fstream>
#include <codecvt>
int main()
{
std::wstring str = L"abàdëef€hhhhhhhµa";
std::wofstream fout(L"C:\\app.log.txt", ios_base::app); //change this to ios_base::in or ios_base::out as per relevance
std::locale loc(std::locale::classic(), new std::codecvt_utf8<wchar_t>);
fout.imbue(loc);
fout << str;
fout.close();
}

Related

My program will not open text file. Ofstream CPP

I'm currently new to C++ and I've been watching a tutorial series https://www.youtube.com/watch?v=_bYFu9mBnr4, but I'm having a big issue. My C++ code will not open a file no matter what I do, I've looked online and tried renaming it, the full path, everything I can think of. Here's my code,
#include <iostream>
#include <fstream>
#include <cstring>
#include <cerrno>
#include <filesystem>
int main()
{
std::ofstream file;
file.open("hello.txt");
if (!file.is_open())
{
std::cerr << "Error: " << strerror(errno) << '\n';
std::cout << std::filesystem::current_path() << std::endl;
}
file << "hello!";
file.close();
return 0;
}
Sorry about this question, it may have been a dumb issue. Turns out IT WAS my antivirus. Avast kept blocking it, it was just looking out for me. I decided to change my antivirus afterwards and it now works fine!

Why is this not producing a file in the current directory?

I have some trouble with producing files in C++. I consulted this answer here but when I try using it, it doesn't produce a file. What I wrote:
//~/Documents/Test_CPP/ex2/main_2.cpp
#include <fstream>
int main()
{
std::ofstream file("Hello.txt");
// Hello.txt has been created here
}
I compile it with the command g++ main_2.cpp and run it with ./a.out. I don't really know what could go wrong here, except theorizing that the file might be produced not in the current directory but somewhere else. So I tried changing Hello.txt to ~/Documents/Test_CPP/ex2/Hello.txt, which doesn't change anything. What exactly am I doing wrong here?
I have encountered this problem on macOS with Xcode if you use some IDEs you should point to build-dir.
My suggestion: use std::filesystem::current_path(). It will give full path to you elf\exe dir.
#include <string>
#include <iostream>
#include <filesystem>
#include <fstream>
int main() {
std::string file_name{"Hello.txt"};
auto path{std::filesystem::current_path()};
path = path / file_name;
if (std::filesystem::exists(path)) {
std::filesystem::remove(path);
}
std::ofstream out_stream(path, std::ios::out);
if (!out_stream.is_open()) {
std::cerr << "Error open file" << std::endl;
return -1;
}
out_stream << "test" << std::endl;
out_stream.close();
return 0;
}
This can sometimes happen if you do not properly terminate the connection to the file
EG.
file.close();
This must be done before the program terminates.

Default write file to desktop

Is there a default code in c++ to write a file(.txt) to a desktop, which could be used for any computer without knowing the leading /desktop?
The most portable way is to use Qt, namely QStandardPaths.
The standard library does not have any off-hand support for it, so you will either need to reinvent the wheel or find a robust solution that already exists. Qt is such a thing.
QStandardPaths::DesktopLocation 0 Returns the user's desktop directory.
In which case, you could use QFile as well as ofstream to write the file to that folder. You would only need to depend on QtCore for this.
The code would look like this:
#include <QFile>
#include <QStandardPaths>
#include <QDebug>
#include <QTextStream>
...
QFile file(QStandardPaths::locate(QStandardPaths::DesktopLocation, ""));
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
qDebug() << "Failed to open";
QTextStream out(&file);
// Done, yay!
This will gently work across distributions and operating systems that QtCore supports, including, but limited to:
Windows
Linux
Mac
QNX
and so forth.
Use SHGetKnownFolderPath with FOLDERID_Desktop (Vista and later), alternatively SHGetFolderPath with CSIDL_DESKTOP to obtain the folder that represents the desktop for the current user. Depends on your Windows version targets, there's several functions, and some of them deprecated.
Just use standard header fstream with getenv:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <sstream>
using namespace std;
int main (int argc, char **argv)
{
if(argc != 2)
{
cerr << "usage: " << argv[0] << " filename" << endl;
return 1;
}
std::ostringstream oss;
#ifdef _WIN32
oss << getenv("HOMEDRIVE") << getenev("HOMEPATH");
#else
oss << getenv("HOME");
#endif
oss << "/" << argv[1];
ofstream f;
f.open (oss.str().c_str());
f << "bar";
f.close();
return 0;
}

How to truncate a file while it is open with fstream

I know it is possible to truncate a file with
std::fstream fs(mypath, std::fstream::out | std::fstream::trunc);
but I need to read the file, truncate it, then write new contents all with the same file handle (so the whole operation is atomic). Anyone?
I don't think you can get "atomic" operation but using the Filesystem Technical Specification that has now been accepted as part of the Standard Library (C++17) you can resize the file like this:
#include <fstream>
#include <sstream>
#include <iostream>
#include <experimental/filesystem> // compilers that support the TS
// #include <filesystem> // C++17 compilers
// for readability
namespace fs = std::experimental::filesystem;
int main(int, char*[])
{
fs::path filename = "test.txt";
std::fstream file(filename);
if(!file)
{
std::cerr << "Error opening file: " << filename << '\n';
return EXIT_FAILURE;
}
// display current contents
std::stringstream ss;
ss << file.rdbuf();
std::cout << ss.str() << '\n';
// truncate file
fs::resize_file(filename, 0);
file.seekp(0);
// write new stuff
file << "new data";
}
File streams don't support truncation except when opening a file. Also, the operations wouldn't be "atomic" anyway: at least, on POSIX systems you can happily read and write a file already opened by another process.
C++ 11 supports swap on ofstream. The best that I could imagine doing would be to open an empty file and call swap. This would not be atomic, but as close as you can get.

Why don't I get any file output with wofstream? [duplicate]

I wrote the following program using VS2008:
#include <fstream>
int main()
{
std::wofstream fout("myfile");
fout << L"Հայաստան Россия Österreich Ελλάδα भारत" << std::endl;
}
When I tried to compile it the IDE asked me whether I wanted to save my source file in unicode, I said "yes, please".
Then I run the program, and myfile appeared in my project's folder. I opened it with notepad, the file was empty. I recalled that notepad supported only ASCII data. I opened it with WordPad, it was still empty. Finally the little genius inside me urged me to look at the file size and not surprisingly it was 0 bytes. So I rebuilt and reran the program, to no effect. Finally I decided to ask very intelligent people on StackOverflow as to what I am missing and here I am :)
Edited:
After the abovementioned intelligent people left some comments, I decided to follow their advice and rewrote the program like this:
#include <fstream>
#include <iostream>
int main()
{
std::wofstream fout("myfile");
if(!fout.is_open())
{
std::cout << "Before: Not open...\n";
}
fout << L"Հայաստան Россия Österreich Ελλάδα भारत" << std::endl;
if(!fout.good())
{
std::cout << "After: Not good...\n";
}
}
Built it. Ran it. And... the console clearly read, to my surprise: "After: Not good...".
So I edited my post to provide the new information and started waiting for answers which would explain why this is and what I could do. :)
MSVC offers the codecvt_utf8 locale facet for this problem.
#include <codecvt>
// ...
std::wofstream fout(fileName);
std::locale loc(std::locale::classic(), new std::codecvt_utf8<wchar_t>);
fout.imbue(loc);
In Visual studio the output stream is always written in ANSI encoding, and it does not support UTF-8 output.
What is basically need to do is to create a locale class, install into it UTF-8 facet and then imbue it to the fstream.
What happens that code points are not being converted to UTF encoding. So basically this would not work under MSVC as it does not support UTF-8.
This would work under Linux with UTF-8 locale
#include <fstream>
int main()
{
std::locale::global(std::locale(""));
std::wofstream fout("myfile");
fout << L"Հայաստան Россия Österreich Ελλάδα भारत" << std::endl;
}
~
And under windows this would work:
#include <fstream>
int main()
{
std::locale::global(std::locale("Russian_Russia"));
std::wofstream fout("myfile");
fout << L"Россия" << std::endl;
}
As only ANSI encodings are supported by MSVC.
Codecvt facet can be found in some Boost libraries. For example: http://www.boost.org/doc/libs/1_38_0/libs/serialization/doc/codecvt.html
I found the following code working properly. I am using VS2019.
#include <iostream>
#include <fstream>
#include <codecvt>
int main()
{
std::wstring str = L"abàdëef€hhhhhhhµa";
std::wofstream fout(L"C:\\app.log.txt", ios_base::app); //change this to ios_base::in or ios_base::out as per relevance
std::locale loc(std::locale::classic(), new std::codecvt_utf8<wchar_t>);
fout.imbue(loc);
fout << str;
fout.close();
}