ifstream + opening random txt file (c_str) - c++

I want to open a random .txt file and put the data into some strings.
It works if I write the path into the code.
I don't get it why this doesn't work.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
string file;
ifstream filein(file.c_str());
cout << "Insert Path" << endl;
cin >> file;
cout << file << endl;
filein.open(file.c_str(), ios::in);
for (string line; getline(filein, line);) {
cout << line << endl;
}
return 0;
}

Your filename string is empty because std::string defaults to empty.
You are passing an empty string (or the nul string) to the ifstream constructor, which is at best, undefined behavior.

Try writing your code like this:
#include <iostream>
#include <fstream>
int main()
{
std::string file;
std::cout << "Insert Path" << std::endl;
std::getline(std::cin, file);
std::cout << file << std::endl;
std::ifstream filein(file);
for (std::string line; std::getline(filein, line); )
{
std::cout << line << std::endl;
}
return 0;
}
Notable edits include:
We're now constructing the ifstream object only when we need it, after file has had data stored, which means no more undefined behavior, and that we only attempt to open a file after we know what the path is.
We're retrieving a whole line when storing to file, instead of only the first word, which is crucial if your path includes any spaces.
We're just using the file string directly. There's no need to call c_str().
We're no longer using using namespace std;. There are many, many reasons why this is bad practice.
EDIT:
If you have a C++17-compliant compiler, I'm going to propose you write code that looks like this instead:
#include <iostream>
#include <fstream>
//You may need to write #include <experimental/filesystem>
#include <filesystem>
#include <string>
int main()
{
std::string input_line;
std::cout << "Insert Path" << std::endl;
std::getline(std::cin, input_line);
//You may need to write std::experimental::filesystem
std::filesystem::path file_path{input_line};
//This will print the "absolute path", which is more valuable for debugging purposes
std::cout << std::filesystem::absolute(file_path) << std::endl;
std::ifstream filein(file_path);
for (std::string line; std::getline(filein, line); )
{
cout << line << endl;
}
return 0;
}
Explicit use of path objects will make your code more readable and make errors more explicit, as well as grant you access to behavior you otherwise would not be able to access.

first what are you opening? as long as you string doesn't contain anything??
second even if the string contains a valid path and the opening was successfull at the first time but in the second will fail as long as you use the same file stream on multiple files without clearing its buffer and closing the previous file:
string file "C:\\MyProject\\data.txt"; // let's say a valid path
ifstream filein(file.c_str());
if(filein.fail()) // the condition fails as long as the opening was successfull
cout << "failed to open file!" << endl;
cout << "Insert Path" << endl;
cin >> file; // let's say the user enters a valid path again: "C:\\MyProject\\test.txt"
cout << file << endl;
filein.open(file.c_str(), ios::in); // fail to correct it:
filein.close();
filein.clear(); // very important
filein.open(file.c_str(), ios::in); // now it's ok!
for (string line; getline(filein, line);) {
cout << line << endl;
}

Related

How to load data into a vector from a text file that has been created inside the same program. in C++

I want to load data from a Text file that has been created in the same program into a vector of strings. But no line of text is getting pushed into the vector here.
Here First I am reading data from some input file and then doing some operations (Removing extra spaces) on it then I save this file as "intermediate.txt". This intermediate.txt is being created and all the operations that I want to do happen successfully. Finally, I want to read this file into a vector<string> code but it doesn't work. I can't store anything in the vector<string> code. Its size is Zero.
#include <bits/stdc++.h>
using namespace std;
int main()
{
string inputFileName;
cout << "Enter the Input File Name: ";
cin >> inputFileName;
ifstream f1(inputFileName);
ofstream f0("intermediate.txt");
string text_line;
while (getline(f1, text_line))
{
string word;
istringstream text_stream(text_line);
while (text_stream >> word)
{
f0 << word << " ";
}
f0 << "\n";
}
f0.close()
ifstream file("intermediate.txt");
vector<string> code;
string line;
while (getline(file, line, '\n'))
{
code.push_back(line);
}
for (auto it : code)
{
cout << it << "\n";
}
}
Here's a mini-code review:
#include <bits/stdc++.h> // Don't do this; doesn't even compile for me
using namespace std; // Don't do this either
int main()
{
string inputFileName;
cout << "Enter the Input File Name: ";
cin >> inputFileName;
ifstream f1(inputFileName); // Bad name
ofstream f0("intermediate.txt"); // Bad name
// You never check that you successfully opened *any* files.
string text_line;
/*
* You don't describe why this is necessary, can a line not be read and
* written as-is? Is it already a line of space-separated variables?
*
* In any case, this is where you already have the words; so store them in
* the vector here as well.
*/
while (getline(f1, text_line))
{
string word;
istringstream text_stream(text_line);
while (text_stream >> word)
{
f0 << word << " ";
}
f0 << "\n";
}
f0.close() // Forgot your semi-colon
// Left f1 open, that's bad practice
ifstream file("intermediate.txt");
vector<string> code;
string line;
/*
* I would hope you felt that reading from a file, writing to a new file,
* closing both files, opening the new file, and reading from the new file
* into the vector was wasteful.
*/
while (getline(file, line, '\n'))
{
code.push_back(line);
}
for (auto it : code)
{
cout << it << "\n";
}
}
The most immediate issue with your original question was that you tried to open the same file in two different streams. The second time, the file failed to open, but because you never check if you actually opened the file, you assumed everything worked fine, but it didn't, which brought you here.
However, there is a better way.
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main() {
std::string inputFileName;
std::cout << "Enter the Input File Name: ";
std::cin >> inputFileName;
// Always check that you successuflly opened the file.
std::ifstream fin(inputFileName);
if (!fin) {
std::cerr << "Error opening: " << inputFileName << ". Exiting...\n";
return 1;
}
std::ofstream fout("intermediate.txt");
if (!fout) {
std::cerr << "Error opening: intermediate.txt. Exiting...\n";
return 2;
}
std::vector<std::string> code;
std::string text_line;
while (std::getline(fin, text_line)) // You've read the line
{
std::string word;
std::istringstream text_stream(text_line);
while (text_stream >> word) {
fout << word << " ";
}
fout << "\n";
code.push_back(text_line); // Just store it while you have it
}
fin.close(); // Best practice is to close a file as soon as you're done
fout.close(); // with it. Don't hog resources.
for (const auto& it : code) // Avoid making copies
{
std::cout << it << "\n";
}
}
The while loop, where you read the lines that you want to store in the vector, now writes to your file and stores the lines into the vector. We also now check whether we successfully opened files, and we close the file streams as soon as we're done with the file so as to not keep it locked for no good reason.
A good next step for improving this program a bit more would be to avoid asking the user for a file name. Instead, take it as an argument to main(). That way, someone only has to type ./a.out input.txt on the command line and the program will do the job automatically.

Empty content in output out from while cycle

I want to load data from .txt file to variable and working with them (like calculate). When I open data, I can read them, but I don´t know to work with data.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
fstream newfile;
string file;
newfile.open("zadanie.txt", ios::in);
if (newfile.is_open()) {
while (getline(newfile, file)) {
cout << file << "\n"; //I GET OUTPUT CORRECTLY
}
newfile.close();
}
else
cout << "Error. \n";
cout << file << "\n"; //HERE IS PROBLEM. OUTPUT IS EMPTY
return 0;
}
I tried global variable, but it not solved. What should I do to correct it? Thanks
What you call "PROBLEM" in the comment is not a problem. file never contains more than a single from the file. The last call to getline will not read a line because there is nothing left in the file when you reach its end. So when you call
std::cout << file;
after that loop, it is to be expected that file is empty. If you want to use the lines later you should store them somewhere, eg in a std::vector<std::string>> :
int main()
{
fstream newfile;
std::vector<std::string> data; // vector to hold all lines
newfile.open("zadanie.txt", ios::in);
if (newfile.is_open()) {
string line; // better name (file->line)
while (getline(newfile, line)) {
cout << line << "\n";
data.push_back(line); // add the line to data
}
newfile.close();
}
else
cout << "Error. \n";
for (const auto& l : data) std::cout << l << '\n';
return 0;
}

C++ Clearing content of text file between runs causes only last line to be written

I am trying to write a few lines into a text file. I would like to empty the file before appending to it, on each run. I am able to clear the previous content, but when I do so, for some reason only the last line of my input file is appended to the output file. I also tried using remove() to erase the file and received the same output.
On the other hand without clearing the file or removing it, everything is appended properly to the output file.
I would be happy to find a way to solve this and perhaps understand why this occurs. I am using C++11.
I looked here: How to clear a file in append mode in C++
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <stdio.h>
int main() {
std::fstream infile;
std::string line;
infile.open("file.txt" , std::ios::in);
while (std::getline(infile, line)) {
std::istringstream line_buffer(line);
std::string word;
std::fstream outfile;
outfile.open("out.txt", std::ios::out);
outfile.close();
outfile.open("out.txt", std::ios::app);
while (line_buffer >> word) {
std::cout << word << " ";
outfile << word << " ";
}
std::cout << std::endl;
outfile << std::endl;
}
return 0;
}
The problem is that you are clearing the file at each iteration of the while loop, you can just open the outfile before the loop like this:
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <stdio.h>
int main() {
std::fstream infile;
std::string line;
infile.open("file.txt" , std::ios::in);
std::fstream outfile;
outfile.open("out.txt", std::ios::out);
while (std::getline(infile, line)) {
std::istringstream line_buffer(line);
std::string word;
while (line_buffer >> word) {
std::cout << word << " ";
outfile << word << " ";
}
std::cout << std::endl;
outfile << std::endl;
}
outfile.close();
return 0;
}

C++ copying another file

i was wondering how to use c++ ifstream/ofstream to copy a file and save it as another name.
this is as far as i got. I know how to get the file, its just that i don't know how to copy that file and save it as a different name.
#include<iostream>
#include<fstream>
#include<string>
namespace std;
int main()
{
ofstream
ifstream
cout << "enter your file you want to copy"<< endl;
cin >> input_file_name;
in_file.open(input_file_name);
if (!in_file)
{
cout <<" there is no such file"<<endl;
return 0;
}
cout <<" enter the name you want to save this copy file"<<endl;
cin >> output_file_name;
out_file.open(output_file_name);
if (!out.file)
{
cout<<"file is not available"<<endl;
return 0;
}
in_file.close();
out_file.close();
return 0;
}
rdbuf with overloaded << is standard way to go.
ifstream src;
ofstream dst;
src.open("from", ios::in | ios::binary);
dst.open("toto", ios::out | ios::binary);
dst << src.rdbuf();
src.close();
dst.close();
Copy a file and save it on another file:
#include <fstream>
#include <iostream>
#include <string>
int main(int arc, char* argv[]) {
std::ifstream file1(argv[1]);
std::ofstream file2(argv[2]);
std::string line;
if (file1.good() && file2.good()) {
while (getline(file1, line)) {
file2 << line;
file2 << '\n';
}
}
file1.close();
file2.close();
}
Basically you want to read a character at a time and write said character to the output stream. There's a get() overload which accepts a streambuf output variable that would work. You could also use the example on cplusplus.com rdbuf documentation.
http://www.cplusplus.com/reference/fstream/ofstream/rdbuf/
This code below should give you a sense of what you want to do.
There are few things you should keep in mind, for example:
is the path of the file giving to read is valid?
or do you want to save the data from an output file if that file exists, before pushing new data?.
You could test this code by just creating a file into your desktop or any location, just change the filePath and destinationPath variables then run the code. (c++ 11)
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<string> readFromFile(const char *filePath) {
vector<string> container;
ifstream obj(filePath); // automatically our file would be open
if (obj.is_open()) { // we check anyways
string line = "";
while(getline(obj, line)) {
if (!line.empty()) // prevent us to insert empty line into our vector
container.push_back(line);
}
obj.close(); // close after we finish reading to avoid corruption
}
return container;
}
bool pipingToDestination(vector<string>data, const char *filePath) {
std::filebuf fb; fb.open(filePath,std::ios::out); // open the file
ostream obj(&fb);
if (!data.empty() && fb.is_open()) { // make sure we have some data && the file file is open to write
for (string x: data) { // c++11
obj << x << endl;
}
fb.close();
return true;
}
return false;
}
int main() {
string filePath = "/Users/lamar/Desktop/testFile.txt";
vector<string> data = readFromFile(filePath.c_str());
cout << "File has passed data into container ... \n";
for(string x: data) {
cout << x << endl;
}
cout << "Creating destination file \n";
string destinationPath = "/Users/lamar/Desktop/destFile.txt";
cout << "has piped data into file " << boolalpha << pipingToDestination(data, destinationPath.c_str());
return 0;
}
This is not the only way to do this, but this code should put you on a direction

Using fstream write

I am trying to look for a line in a specified file and replace it with my line. I don’t have access to the library on the machines I’ll be running this on, so I created a custom file. The trouble seems to be the write call to the fstream object. I was wondering if any of you can help. Also, my getline loop stops before reaching the end of the file, and I am not sure why.
#include <iostream>
#include <fstream>
#include <string>
#define TARGET2 "Hi"
using namespace std;
void changeFile(string fileName){
fstream myStream;
myStream.open(fileName.c_str(),fstream::in | fstream::out);
string temp;
string temp2 = "I like deep dish pizza";
while(getline(myStream, temp)){
if(temp == TARGET2){
cout << "Match" << endl;
myStream.write(temp2.c_str(), 100);
myStream << temp2 << endl;
cout << "No runtime error: " << temp2 << endl;
}
cout << temp << endl;
}
myStream.close();
}
int main (void){
changeFile("Hi.txt");
return 0;
}
Hi.txt
Hi
Today is June 18
I like pizza
I like pepperoni
The output is:
Match
No runtime error: I like deep dish pizza
Hi
myStream.write(temp2.c_str(), 100);
myStream << temp2 << endl;
Why are you writing this to the file twice, and why are you telling it that "I like deep dish pizza" is 100 characters long? Just using the second line alone should do what you want.
I think the reason the loop is ending is that you're writing the file as you read it, which causes getline to be confused. If the file is small, I would just read the whole thing into a stringstream, replacing the line you want to replace, then write the whole stringstream out to a file. Changing the file in-place is much harder.
Example:
#include <fstream>
#include <iostream>
#include <sstream>
int main(int argc, char** argv) {
/* Accept filename, target and replacement string from arguments for a more
useful example. */
if (argc != 4) {
std::cout << argv[0] << " [file] [target string] [replacement string]\n"
<< " Replaces [target string] with [replacement string] in [file]" << std::endl;
return 1;
}
/* Give these arguments more meaningful names. */
const char* filename = argv[1];
std::string target(argv[2]);
std::string replacement(argv[3]);
/* Read the whole file into a stringstream. */
std::stringstream buffer;
std::fstream file(filename, std::fstream::in);
for (std::string line; getline(file, line); ) {
/* Do the replacement while we read the file. */
if (line == target) {
buffer << replacement;
} else {
buffer << line;
}
buffer << std::endl;
}
file.close();
/* Write the whole stringstream back to the file */
file.open(filename, std::fstream::out);
file << buffer.str();
file.close();
}
Run like:
g++ example.cpp -o example
./example Hi.txt Hi 'I like deep dish pizza'