fstream doesn't resolve path - c++

i am new to c++ and trying to write a simple function, that saves a string to a file.
The function works, when i pass the full path to fstream, but it doesn't resolve relative paths.
Here is the relevant part of my code
#include <iostream>
#include <fstream>
void writeToFile ()
{
std::fstream fs;
fs.open ("/home/blabla/Documents/test.txt", std::fstream::in | std::fstream::out | std::fstream::app);
fs << " test content";
fs.close();
}
This works fine, but i would like to create the file in the folder, where my program is executed, so i tried this
fs.open ("./test.txt", std::fstream::in | std::fstream::out | std::fstream::app);
I also tried
fs.open ("~/Documents/test.txt", std::fstream::in | std::fstream::out | std::fstream::app);
Neither of them created a new file and i did not get any error message.
I found this post, which suggests, that i can pass relative paths to fstream but only gives windows examples.
How to use fstream objects with relative path?
I work on Linux Mint, the target environment is debian.
I am thankful for any hints or suggestions,
Michael

Relative paths do work with streams. You have two interesting cases though. The tilde (~) is a special character that some shells interpret. I suspect that fstream doesn't do that interpretation. As to the example of "./test.txt", I think the previous comment is correct - that file has been created - it's just not where you expected it.

Your program
#include <iostream>
#include <fstream>
void writeToFile () {
std::fstream fs;
fs.open ("./test.txt", std::fstream::in | std::fstream::out | std::fstream::app);
fs << " test content";
fs.close();
}
int main() {
writeToFile();
}
works perfectly fine for me on Coliru.
As you can see from the ls output, the file was created
a.out << The executable program
main.cpp << The source
test.txt << The created text file
and cat at least dumps the content of the file
test content
As mentioned in my comment, a path like ~/Documents/test.txt is evaluated by the shell, while ./test.txt should work for openting an existing file, if you're running your program in the same directory where the file exists.
"Neither of them created a new file and i did not get any error message."
You'll never get any kind of error message, if std::fstream::open() failed for some reason.
You have to check for the stream state after that call, like e.g.
if(!fs) { std::cerr << "Could not open file" << std::endl; }
You may e.g. not have rights to create a file in this directory.
Another option is to use the std::basic_ios::exceptions() function of std::fstream(), to trigger an exception when the stream state runs into an error condition.

Related

Errors in relative path

So this is a simple C++ program for reading a file and displaying its contents.
My directory structure is as follows
Project Directory
|
Data___
| |
| data.txt
|
program1.cpp
and The program:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
char char1;
fstream data; // Because I wanna to write to this file later.
data.open("../Data/data.txt",ios::out | ios::in);
if (data.is_open()) {
for (int i = 0; !data.eof(); ++i) {
data.get(char1);
cout << char1 << endl;
}
data.close();
}
return 0;
}
So currently my program works fine... However when I use:
data.open("Data/data.txt",ios::out | ios::in);
The program doesn't work. Why is this so? Ideally the above mentioned code piece should work since the Data folder is in the same directory as my cpp file.
data.open("../Data/data.txt",ios::out | ios::in);
By using 2 dots we are going back a directory and the Data folder isn't there.
Then why is the program working using the 2 dots?
Looking at your directory structure, I see that both your program1.cpp and data.txt are in the same "Data" folder. Since you are already inside the Data folder, "Data/data.txt" looks for another Data folder. In UNIX ".." means the previous directory. So when you use ".." you go to "Project Directory", which contains a "Data" folder. That is why data.open("../Data/data.txt",ios::out | ios::in) is working. You can also try using the following:
data.open("data.txt",ios::out | ios::in);

Can't write/read with fstream

When i write like this
std::fstream file ("data.dat", std::ios::in | std::ios::out);
if (!file)
{
std::cerr << "Error";
exit(1);
}
I receive "Error". When i rewrite the whole thing like this
std::fstream file;
file.open("data.dat", std::ios::out | std::ios::in);
if (!file)
{
std::cerr << "Error";
exit(1);
}
data.dat is being created, and i manage to write and read. Am doing this on VS 2013, in addition to that i tried compiling on 6.0 version and both ways have worked. I have no clue what the problem is.
You get the error because you instructed fstream to open the file for reading as well. If the file does not exist flags in | out will give you an error. Try it with only out and it should work. If you want to do write and read on a file that does not exist you need an extra flag, either append (app) or truncate (trunc)

fstream is not writing anything on the file

I'm trying to write some things to a text file but it won't even create the file. I will appreciate a lot if you can help me with this. Thanks.
#include <fstream>
#include <iostream>
int main(){
std::ofstream file;
file.open("path/to/file");
//write something to file
file << "test";
//printing to screen
std::cout << file.rdbuf();
//closing file
file.close();
return 0;
}
The following line is your culprit:
std::cout << file.rdbuf();
You cannot use rdbuf to output a file that was opened for write operations only.
Remove that line and your file will be written correctly.
If you want to read your file after you've finished writing to it:
Solution 1:
Open file for both read and write operations using fstream:
std::fstream file("path/to/file", std::ios::in | std::ios::out);
// ... write to file
file.seekg(0); // set read position to beginning of file
std::cout << file.rdbuf();
Solution 2:
Create a new std::ifstream to read from file:
// ... write to file
file.close(); // call `close` to make sure all input is written to file
std::ifstream inputFile("path/to/file");
std::cout << inputFile.rdbuf();
salesFile.open("C:\\Users\\Tebsan\\Desktop\\Coding\\c++\\re\\salesFile.txt"); // ...try to open existing file
if( !salesFile.is_open() ) // ...else, create new file...
salesFile.open("C:\\Users\\Tebsan\\Desktop\\Coding\\c++\\re\\salesFile.txt", ios_base::in | ios_base::out | ios_base::trunc);
You have to call fstream::open with an explicit openmode argument of
ios_base::in | ios_base::out | ios_base::trunc
Otherwise open will fail due to ENOENT.
Thanks for the help!!!
I Learned new things from this. The funny thing is that the issue was the name of the file, apparently the name was too long, and for the new file that included file stream I just added stream at the end of the name, so the compiler kept running the first file (without file stream)...

Appending a new line in a file(log file) in c++

I have a logging functionality and in this I have got log files. Now every time I run the program I want that previously written file should not get deleted and should be appended with the current data (what ever is there in the log file)
Just to make it clear for example: I have a log file logging_20120409.log which keeps the timestamp on a daily basis. Suppose I run my project it writes to it the current timestamp. Now if I rerun it the previous timestamp gets replaced with it. I do not want this functionality. I want the previous time stamp along with the current time stamp.
Please help
You want to open the file in "append" mode, so it doesn't delete the previous contents of the file. You do that by specifying ios_base::app when you open the file:
std::ofstream log("logfile.txt", std::ios_base::app | std::ios_base::out);
For example, each time you run this, it will add one more line to the file:
#include <ios>
#include <fstream>
int main(){
std::ofstream log("logfile.txt", std::ios_base::app | std::ios_base::out);
log << "line\n";
return 0;
}
So, the first time you run it, you get
line
The second time:
line
line
and so on.
Use something like:
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ofstream out("try.txt", ios::app);
out << "Hello, world!\n";
return 0;
}
The ios:app option makes the output get appended to the end of the file instead of deleting its contents.
maybe you need to open the file with the append option. like this:
FILE * pFile;
pFile = fopen ("myfile.txt","a");
or this :
fstream filestr;
filestr.open ("test.txt", fstream::app)

fstream in and out on nonexistent file

Is it possible to open an fstream on a file that does not exist with both ios::in & ios::out without getting an error?
To open an fstream on a file that does not exist for input and output (random access) without getting an error, you should provide the flags fstream::in | fstream::out | fstream::trunc in the open (or constructor) call. Since the file does not already exist, truncating the file at zero bytes is no drama.
You may want an error when opening a file that doesn't exist when specifying only ios::in since you'll never be able to read from the stream so failing early in this case will prevent surprise failures later on.
The answer to your question unfortunately is: "No", this is not possible in a single C++ statement.
Yes, many people will answer, that you can use the combined flags fstream::in | fstream::out | fstream::trunc. But that answer is nonsense. fstream::trunc means, that the output file will be truncated to size zero upon opening. But then, why would you like to open an empty file for reading and writing? Except for the rare case, that you need a file as a temporary store for some of your application's data, that you will first write and later read back, there is no use for this flag combination.
Some people recommend to first try to open with fstream::in | fstream::out (and possible further flags like fstream:app or fstream::binary as needed) and then check the file's error status: If the file could not be opened, then re-try the open operation including | fstream::trunc. This solution has several caveats, however. For example, if your file system is mounted via NFS, the first attempt to open the file in read/write-mode might fail due to temporary network issues. If the second attempt (the one including the fstream::trunc flag) then succeeds, there goes your wounderful data, that you have collected so far.
The safe solution is to first open the file for appending only (which will create the file, if it doesn't exist, but will not truncate it) and then close it immediately and open it a second time in read-write mode. This can be achieved with the following code: Note, that an ofstream is first constructed and then immediately discarded.
std::string filename { "test.txt" };
(void) std::ofstream(filename, std::ostream::app);
std::fstream file(filename);
Alternatively, if you need further flags, like binary, use:
std::string filename { "test.txt" };
(void) std::ofstream(filename, std::ofstream::app | std::fstream::binary);
std::fstream file(filename, std::fstream::in | std::fstream::out | std::fstream::binary);
I hope, that in C++25 (or whichever standard is next), they finally add a flag std::fstream::create to create non-existant output files, if read-write-mode is requested.
#include <fstream>
ofstream out("test", ios::out);
if(!out)
{
cout << "Error opening file.\n";
return 1;
}
ifstream in("test", ios::in);
if(!in)
{
cout << "Error opening file.\n";
return 1;
}
If an error occurs the message is displayed and one (1) is returned. However it is possible to compile and execute just ofstream out("test", ios::out); and ifstream in("test", ios::in); without any errors. Either way the file test is created.
#include <iostream>
#include <fstream>
using namespace std;
int main () {
fstream f("test.txt", fstream::in | fstream::out);
cout << f.fail() << endl;
f << "hello" << endl;
f.close();
return 0;
}
This code will print 1 and will not create "test.txt" file, if it does not exit. So it is not possible to open and fstream on a file that does not exist without getting an error.
std::fstream f("test.txt", std::ios_base::out);
f.close(); //file now exists always
f.open("test.txt", fstream::in | std::ios_base::out);
//f is open for read and write without error
I haven't checked to guarantee that it will open without error, but I feel pretty confident that it should.