C++ std::stringstream/ostringstream and UTF characters - c++

I'm writing a program which processes some data, outputs it to a .csv file, then writes a GNUplot script, and calls GNUplot to execute the script and create an image file all with the same name (only different extensions). The filenames contain UTF characters (UTF-8 I believe?) such as °, φ and θ. All of this works perfectly fine when I compile and execute it in Linux with g++ 4.4.7. I then altered my code to compile in Microsoft Visual Studio 2008, and the problems start when I run the program.
I use the following two bits of code to
Make a standard filename string (to which I just add extensions for the various files)
Open a stream to write to a file (the only difference between the GNUplot script and the .csv files is the extensions
// Generate a file name string
stringstream ss;
ss << type << " Graph #" << gID << " - " << title;
string fileName = ss.str();
// Open a stream for the output file
ostringstream outfile;
outfile << fileName << ".gplt" << ends;
ofstream ofs( outfile.str().c_str() );
The contents of the ofstream files where ofs writes contain the UTF characters properly, however the stringstream-created string fileName and the ostringstream created filename (even when not created with fileName, I tested it) show the characters incorrectly.
Example:
What it should be - CDFvsRd Graph #32 - MWIR # 300m, no-sun, 30kts, θ=all°.csv
What it ends up as - CDFvsRd Graph #32 - MWIR # 300m, no-sun, 30kts, Ï=allË.csv
What can I do to remedy this, with as much standard C++ as possible? Would converting my fileName string to wstring help?

The solution was to write the Windows portion of the code to not export the filenames without the graph titles, omitting the UTF-8 characters from the filename. This wasn't a true solution, only a workaround.

Related

C++ Reading a text file has extra spaces between characters

We are using C++ on windows and Linux and UNIX and are reading a text file. On Windows with some files we are getting extra spaces between characters in a line.
I have seen an article that seems to explain this but we are getting errors.
C++ getline adding spaces
When we read some files created by applications on Windows there is a space between characters. When we create a text file in Windows it does not have extra spaces.
fstream file;
string fileline;
file.open(configuration_file, ios::in|ios::out);
// This line was added from the post and we get errors
file.imbue(std::locale(file.getloc(), new std::codecvt_utf16<char, 0x10FFFF, std::consume_header>));
if (!file){
print_progress("Configuration File does not exist\n");
}
else {
while(!file.eof()) {
getline(file, fileline);
std::cout << std::string(fileline) + "\n";
}
}
file.close();
How do we resolve this in C++? Is there a library that manages this?
Many thanks

Phantom \.txt file in windows

It seems like it is possible to create a file \.txt in windows that can be read, but I'm not able to access it any other way or see if it exists. This seems to only work for \.txt since I can't create other files with backslashes in it such as a\.txt
string filename = "\\.txt";
// make file
ofstream writer(filename);
writer << "This file exists" << endl;
writer.close();
// read file
ifstream reader(filename);
string line;
getline(reader, line);
cout << line << endl;
reader.close();
When I use ls -lia in bash, this file doesn't show up at all, but the program above reads it fine (I can remove the part that creates the file and run it later so the file does persists), how does this work?
On Windows, ofstream writer("\\.txt") creates a file named .txt in the root of the current drive. It is a perfectly valid file name.
ofstream writer("a\\.txt") tries to create a file named .txt in the a subdirectory of the current directory. The a directory must exist in order for it to succeed. Most likely it does not exist, therefore it fails for you.
To create a directory you can use either the mkdir function (which has compatibility problems with other OSes because Windows is not POSIX compatible), or the CreateDirectory WINAPI function, that is Windows specific. After calling CreateDirectoryA("a"), the "a\\.txt" path should work.

Is there a way to read in a folder of files in C++?

I have a folder containing close to 200 word documents, and I want to read them in to C++ using ifstream fin from library fstream. I have two problems:
1) fin is able to read in .doc files, but nonsense is printed to the screen because .doc files are not plain text.
2) I know of no way to get a program to automatically read in multiple files with unrelated file names.
Because of these two problems, I am manually going through each of my .doc files and changing them to .txt files. In addition, I am calling them 1.txt, 2.txt, 3.txt, etc, so that I can use a for loop in C++ to read them all in (I would convert the loop control variable i to a string x in each iteration, and read in "x.txt").
While this will work, I've only finished going through 83 files and it's taken around an hour. Is there a way for me to get C++ to automatically read all these files in? C++ would have to first change each one to a .txt file as well, so that I can print meaningful text to the screen.
Boost library is very rich for these type of file / filesystem operations. Please check the code below. This basically goes to the folder (ws) where you keep all your doc files, and iterates through all the files in it. The code assumes that the folder 'ws' has only files, no folders. Once you have the name of the file you can do all kinds of manipulation on it.
I didn't get why you want to change the extension to txt but included a few lines that does this. Changing the extension won't affect its content.
#include <sstream>
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main(){
// ref : https://theboostcpplibraries.com/boost.filesystem-paths
// ws : workspace where you keep all the files
fs::path ws = fs::path(getenv("HOME")) / "ws";
// ref : https://theboostcpplibraries.com/boost.filesystem-iterators
fs::directory_iterator it{ws};
while (it != fs::directory_iterator{}){
std::cout << "Processing file < " << *it << " >" << std::endl;
// ... do other stuff
// Parse the current filename into its parts, then change the extension to txt
// ref : https://theboostcpplibraries.com/boost.filesystem-paths
std::stringstream ss;
ss << (ws / fs::path(*it).stem()).native() << ".txt";
fs::path new_path(ss.str());
std::cout << "Copying into < " << new_path << " >" << std::endl;
// ref : http://www.boost.org/doc/libs/1_53_0/libs/filesystem/doc/reference.html
fs::copy_file(*it++, new_path, fs::copy_option::overwrite_if_exists);
}
return 0;
}
You can compile with this :
g++ -std=c++14 -o main main.cc -lboost_filesystem -lboost_system
Given that you are talking about Microsoft Word and "folder", I guess you are running Windows.
The Windows API provides the FirstFirstFile / FindNextFile pair of functions, which allow your program to automatically find the names of existing files. The official example is named "Listing the Files in a Directory"
On Linux and Unix platforms, there are functions named opendir and readdir which serve the same purpose.
If you want to write cross-platform code, there are libraries that provide an abstraction layer above the OS functions such as boost::filesystem.

How to change EOL coding in txt files?

I am writing in Visual Studio 2008 in C++ and I have problems with other libraries - they do not accept the line endings (EOL) I generate with my txt files.
How can I change that while writing a file with
std::ofstream myFile;
myFile.open("traindata.txt");
myFile << "stuff" << endl;
// or
//myFile << "stuff" << '\n';
myFile.close();
EDIT 2 :
Ok, I did a mistake in code : I was appending "0 " for every iteration so that I had whitespace before the EOL.
By bad. You guys have been right. Thanks for help.
Is it possible that you just don't want the \n to end of line sequence to happen? Open your file using std::ios_base::binary: this turns off precisely the conversion. ... and don't use std::endl unless you really want to flush the stream:
std::ofstream myFile("traindata.txt", std::ios_base::binary);
myFile << "stuff\n";
The close() is typically also unnecessary unless you want to check that it was successful.
You should open the file stream in binary mode to keep C++ library from converting line endings automatically:
myFile.open("traindata.txt", std::ios_base::out|std::ios_base::binary);
That will keep C++ library from converting '\n' to OS-specific EOL symbol (CR-LF on Windows).
Download notepad++ - that should be able to fix the problem.
Or dos2unix, unix2dos on cygwin
Use myfile << "\r\n" for the Windows-style ending, or myfile << "\n" for the UNIX-style.

C++ ofstream is changing output format randomly?

I have a function that is writing to a .txt file.
ofstream fichier("C:\\users\\me\\Desktop\\test.txt", ios::app);
then :
fichier << "some text here";
The text i'm writing is a log file containing the history of my application changes.
As i'm french, i'm writing characters (latin ?) like "ê" or "ë". This works randomly...At first i get the correct format in notepad then when i append some others characters, it switches to another format so "ê" becomes "ê" and i don't understand why.
(In fact i can't even get "¨" to be compiled by code::blocks because it is a "multi characters constant")
What should i do ?
Thanks by advance.