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'
Related
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;
}
I am writing a program that takes input from a text file (c++ code) and modifies it for output in a text file(html). This program needs to read from standard input and write to standard output. It uses command line arguments -i filename for input and -o filename for output as well as shell input/output redirection. I am fairly new to Linux and not sure how to do this in a efficient manner. Here is what i got so far:
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <string.h>
#include <string>
using namespace std;
int main(int argc, char * argv[]) {
vector<string> mod;
int modNum = 0;
int i = 1;
string input = "";
string inFilename = "";
string outFilename = "";
ifstream inFile;
ofstream outFile;
while(i < argc){
if (strcmp(argv[i],"-i") == 0 ) {
i++;
if (i<argc){
inFilename = argv[i];
} else {
cout << "\t-i require a filename for input" << endl;
}
i++;
} else if (strcmp(argv[i],"-o") == 0 ) {
i++;
if (i<argc){
outFilename = argv[i];
} else {
cout << "\t-i require a filename for output" << endl;
}
i++;
}
}
if (inFilename != "" ) {
inFile.open(inFilename.c_str());
}
if (outFilename != "") {
outFile.open(outFilename.c_str());
}
if (inFile.is_open() and outFile.is_open()) {
outFile << "<script src=\"https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js\"></script>" << endl;
outFile << "<pre class=\"prettyprint\">" << endl;
while (!inFile.eof()) {
getline(inFile, input);
outFile << input << endl;
}
outFile << "</pre>";
} else {
cout << "<script src=\"https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js\"></script>" << endl;
cout << "<pre class=\"prettyprint\">" << endl;
while (cin) {
if (getline(cin,input)) {
cout << input << endl;
}
}
cout << "</pre>";
}
inFile.close();
outFile.close();
}
The problem I am having is there is no versatility with this method. If i get
./c < code.cpp -o page.html
or
./c -i code.cpp > page.html
The program won't execute correctly. I apologize if there is any small errors as i copy and pasted chunks of code to show only the necessities. The program will do more but right now I'm just trying to get input/output to work correctly.
Well, so far you have processed only two out of four cases of running the program: your code assumes that if both -i and -o specified, then it reads from input file and prints to output file, otherwise it reads from input and writes to output. So, naturally, your program cannot read from file and write to standard output (or vice-versa) - code for that is just not here.
I'd suggest you extracting code for processing file in a separate function which takes istream& input and ostream& output as arguments to avoid code duplication. You will call it with different arguments depending on which of the four cases you've encountered, something like:
process_file(inFile.is_open() ? inFile : cin, outFile.is_open() ? outFile : cout);
This will get you further to correct code, but it's still not ideal. I'd suggest going to codereview site to get more feedback.
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;
}
This program is supposed to tell the user how many words and lines are in their program (text file only). The two functions that I have written both work, except the num_of_lines function is counting one more line than is correct every time and the num_of_words function is off by about 300 words every time. Not sure what I am doing wrong here. Any help will be greatly appreciated, thanks. I copy and pasted an output after my code and compared it to wc.
#include <iostream>
#include <fstream>
#include <cctype>
#define die(errmsg) {cerr << errmsg << endl; exit(1);}
using namespace std;
int num_of_words(string name)
{
int cnt2 = 0;
ifstream iwords;
iwords.open(name);
string w;
if(iwords.is_open())
{
while(iwords >> w)
{
cnt2++;
}
}
else cerr <<"can not open" + name << endl;
iwords.close();
return(cnt2);
}
int num_of_lines(string name)
{
int cnt3 = 0;
string line;
ifstream ilines;
ilines.open(name);
if(ilines.is_open())
{
while(getline(ilines, line))
{
cnt3++;
}
}
else cerr <<"can not open" + name << endl;
ilines.close();
return(cnt3);
}
int main(int argc, char **argv)
{
int num_of_lines(string name);
if(argc == 1)die("usage: mywc your_file");
string file;
file = argv[1];
ifstream ifs;
ifs.open(file);
if(ifs.is_open())
{
int b;
b = num_of_words(file);
cout <<"Words: " << b << endl;
}
else
{
cerr <<"Could not open: " << file << endl;
exit(1);
}
ifs.close();
return(0);
}
Zacharys-MBP:c++ Zstow$ my sample.txt
Chars: 59526
Words: 1689
Lines: 762
Zacharys-MBP:c++ Zstow$ wc sample.txt
761 2720 59526 sample.txt
Zacharys-MBP:c++ Zstow$
Most files (especially programs) will end in a new line. You may not see this in your editor but it is probably there. You will have to check the last line to see if it actually contains any content, or if it is empty.
The istream operator (>>) will detect any group of characters between whitespace to be a "word." So if you're parsing programs, you may have:
for(int i=1; i<73; i++)
The istream operator will see 4 words: [for(int, i=1;, i<73;, i++)]
I have coded a programm which can load one text file, can decide how long each word is and can write txt files based on the length of the words. But when i run the programm, the new text files are always filled with just one word(each new word with an already existing text file for his length just overrides the text file)
The start text file looks like this():
http://i.stack.imgur.com/WBaRf.png
My new created text files(named after their length for example: 7.txt) after i runned the programm:
http://i.stack.imgur.com/6QKgE.png
My code:
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main(int argc, char *argv[])
{
char filename[128];
ifstream file;
char line[100];
cout << "Input filename: " << flush;
cin.getline(filename, 127);
file.open(filename, ios::in);
if (file.good())
{
file.seekg(0L, ios::beg);
int number = 0;
while (!file.eof())
{
file.getline(line, 100);
stringstream stream;
stream << line;
number++;
cout <<"Number: "<< number << " length: " << stream.str().length() << " " << line << endl;
std::stringstream sstm;
int laenge = stream.str().length();
string txt = ".txt";
sstm << laenge << txt;
string result = sstm.str();
std::ofstream outFile(result);
outFile << line << endl;
outFile.close();
}
}
else
{
cout << "File not found" << endl;
}
while (true)
{
};
return 0;
}
My goal is that i have sorted the whole words into the file their files, the only problem is that they overwrite themself... How can i get rid off that?
If you don't want to overwrite the content of the file, you can open the file and specify that you want to append to the file:
std::ofstream outFile(result, ios::app);
// ^^^^^^^^