I am trying to use getline on a file (unkown size) to grap the first line, input it into a string, manipulate this string (replace words with others, move some around) and output the manipulated line back to the file.
After this, I need to do the same thing to line 2, 3, etc. until the end of the file. How would I go about doing this? I figured a while loop for getline would work, but not sure how to get the conditions for the while loop or how to manipulate each line individually. Such as lines 1 and 3 must be manipulated differently than lines 2 and 4. etc.
A rough idea of what I'm trying to do:
void readFile(string filename, string text)
{
ifstream infile;
infile.open(filename);
getline(cin, text) // pretty sure this is wrong..
infile.close(); // close here, or after manipulation???
}
void swapText(string filename, string text)
{
string decrypText;
//Manupulate several things..
return decrypText;
}
void writeToFile(string filename, string decrypText)
{
ofstream outfile;
outfile.open(filename);
outfile << decrypText << endl;
outfile.close();
}
The standard idiom for reading text lines from a file and storing them is:
std::vector<std::string> file_data;
std::string text_line;
while (std::getline(my_data_file, text_line))
{
// Optional: store the text line
file_data.push_back(text_line);
// Call a function to process (or ignore) the text line:
Process_Text_Line(text_line);
}
If you want to have a function that reads the file, you may need to pass the vector:
void Read_File(std::vector<std::string>& file_data)
{
//...
// Read the data, see "while" loop above.
}
Don't open and close the file for every read. Keep it open and read a line at a time:
std::istream in("filein.txt");
std::ostream out("fileout.txt");
std::string line;
while (std::getline(in, line)) {
// modify line as appropriate
out << line << '\n';
}
Related
I'm having trouble in understanding some part of this code I've found online, its goal is to print ASCII art from a .txt file. To be more accurate, I'm having trouble in undesrstanding the while loop in line 28 which is part of the string function "getFileContents". What's the meaning of 'TempLine'?
#include <iostream>
#include <fstream>
#include <string>
std::string getFileContents (std::ifstream&); //Gets file contents
int main(int argc, char *argv[])
{
std::ifstream Reader ("File1.txt"); //Open file
std::string Art = getFileContents (Reader); //Get file
std::cout << Art << std::endl; //Print it to the screen
Reader.close (); //Close file
return 0;
}
std::string getFileContents (std::ifstream& File)
{
std::string Lines = ""; //All lines
if (File) //Check if everything is good
{
while (File.good ())
{
std::string TempLine; //Temp line
std::getline (File , TempLine); //Get temp line
TempLine += "\n"; //Add newline character
Lines += TempLine; //Add newline
}
return Lines;
}
else //Return error
{
return "ERROR File does not exist.";
}
}
If you take a look at std::getline(), you can see that the string parameter is passed by non-const reference. This means that the string can (and is) edited by the std::getline() function. So line by line:
// Loop until the file stream cannot read any more input.
while (File.good ())
{
// Create a new, empty string called `TempLine`
std::string TempLine;
// Read a line from `File`, and write it into TempLine.
std::getline (File , TempLine);
// Add a newline character at the end of the string.
TempLine += "\n";
// Add the line we just read from the file to the `Lines` string,
// which holds the full file contents.
Lines += TempLine; //Add newline
// Repeat until all lines have been read from the file (or the file
// becomes otherwise unreadable).
}
The reason TempLine is needed is because std::getline() needs something to read the file content into, and if we passed Lines directly to the function, we'd only ever return the last line of the file (the previous lines would always get overwritten in the string).
I am having an issue in C++ in which a program that I am writing reads a pre-existing text file called Builders.txt and then writes the same information into a new text file called output.txt, however, when I go to run the program the only line visible in the output.txt file is the last line, which is Tom:90:3.
Text file
Reliable Rover:70:1.
Sloppy Simon:20:4.
Technical Tom:90:3.
The expect output from the output.txt file would be the file shown above
Body Program
int main() {
readFile();
writeFile();
getch();
return 0;
}
Implementation file
std::ifstream filereadBuilders("Builders.txt");
std::string input;
void readFile() { //fumction that reads each file.
std::vector < std::string > readBuilders;
//loop to read builders.txt
while (filereadBuilders >> input) {
readBuilders.push_back(input);
}
std::cout << endl;
}
void writeFile() {
std::ofstream file("output.txt");
std::vector < std::string > RAT;
RAT.push_back(input);
for (std::string outputFile: RAT) {
file << outputFile << std::endl;
}
}
I am also having an issue where when it reads/writes, it skips white space. As seen in the expected output file the last line is Technical Tom:90:3., however, my program only returns Tom:90:3., as if its ignoring all white space.
When you use
std::vector<std::string> RAT;
RAT.push_back(input);
you are adding only the last line that was read from the file to RAT. It makes sense that only that line is written to the output file.
Suggestion for future coding projects -- avoid global variables as much as possible.
In your case, make sure that readFile returns the vector of lines to the calling function. Then, pass that data to writeFile. While at it, pass the input file to readFile and pass the output file to writeFile as well.
void readFile(std::string const& inputFile,
std::vector<std::string>& lines)
{
std::ifstream file(inputFile);
std::string line;
// Use getline. This makes sure that even whitespaces are read in.
while(std::getline(file, line))
{
lines.push_back(line);
}
std::cout << endl;
}
void writeFile(std::string const& outputFile,
std::vector<std::string> const& lines)
{
std::ofstream file(outputFile);
for(std::string const& line: lines)
{
file << line << std::endl;
}
}
and call them as
std::vector<std::string> lines;
std::string inputFile = "Builders.txt";
std::string outputFile = "output.txt";
readFile(inputFile, lines);
writeFile(outputFile, lines);
I want to read a file with std::getline. but reads first line only
string FileReader::readLine() {
string line;
string read;
ifstream ReadFile;
ReadFile.open("input.txt");
if (ReadFile.is_open()) {
getline(ReadFile, line);
//ReadFile.close();
}
return line;
}
this is my method. I call this method several time but always reads first line how can i do to read next lines?
You need to change your program flow.
Don't return a string. Use the line within the loop to do whatever it is you want. Ensuring that you either don't leave the method or return to it.
You can't keep coming back to a function like this, as it will keep reading from the beginning.
void FileReader::readLine() {
string line;
string read;
ifstream ReadFile;
ReadFile.open("input.txt");
if (ReadFile.is_open()) {
while(getline(ReadFile, line))
{
//do what you want with that line, but return program flow here.
}
ReadFile.close();
}
}
I have seen how to remove specific chars from a string but I am not sure how to do it with a file open or if you can even do that. Basically a file will be open with anything in it, my goal is to remove all the letters a-z, special characters, and whitespace that may appear so that all that is left is my numbers. Can you easily remove all chars rather than specifying a,b,c etc when the file is open or would I have to convert it to a string? Also would it be better to do this in memory?
My code this far as is follows:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
string filename;
cout << "Enter the name of the data file to open" << endl;
cin >> filename >> endl;
ofstream myfile;
myfile.open(filename);
if (myfile.is_open()) { //if file is open then
while(!myfile.eof()){ //while not end of file
//remove all chars, special and whitespace
}
}
else{
cout << "Error in opening file" << endl;
}
return 0;
}
Preliminary remarks
If I understand well, you want to keep only the numbers. Maybe it's easier to retain chars that are ascii numbers and eliminate the others rather than eliminate a lot of other chars classes and hope that the remainder is only numbers.
Also never loop on eof to read a file. Loop on the stream instead.
finally, you should read from an ifstream and write to an ofstream
First approach: reading strings
You can read/write the file line by line. You need enough memory to store the largest line, but you benefit from buffering effect.
if (myfile.is_open()) { //if file is open then
string line;
while(getline(myfile, line)){ //while succesful read
line.erase(remove_if(line.begin(), line.end(), [](const char& c) { return !isdigit(c); } ), line.end());
... // then write the line in the output file
}
}
else ...
Online demo
Second approach: reading chars
You can read/write char by char, which gives very flexible option for handling individual characters (toggle string flags, etc...). You also benefit from buffering, but you have function call overhaead for every single char.
if (myfile) { //if file is open then
int c;
while((c = myfile.get())!=EOF){ //while succesful read
//remove all chars, special and whitespace
if (isdigit(c) || c=='\n')
... .put(c); // then write the line in the output file
}
}
else ...
Online demo
Other approaches
You could also read a large fixed size buffer, and operate similarly as with the strings (but don't eliminate LF then). The advantage is that the memory need is not impacted by some very large lines in the file.
You could also determine the file size, and try to read the full file at once (or in very large chunks). You'd then maximize performance at the cost of memory consumption.
This is just an example in order to extract all chars you want from a file with a dedicated filter:
std::string get_purged_file(const std::string& filename) {
std::string strbuffer;
std::ifstream infile;
infile.open(filename, std::ios_base::in);
if (infile.fail()) {
// throw an error
}
char c;
while ((infile >> c).eof() == false) {
if (std::isdigit(c) || c == '.') {
strbuffer.push_back(c);
}
}
infile.close();
return strbuffer;
}
Note: this is just an example and it has to be subject to optimizations. Just to give you an idea:
Read more than one char at time, (with a proper buffer).
Reserve memory in string.
Once you have the buffer "purged" you can overwrite your file on save the content into another file.
I have a function that I want to take a file, look at the words in the file, position them in alphabetical order and replace the file with that. So far, I have it to get the words in alphabetical order. The problem is, is that it only saves the last word to the file.
Here is my current code:
void thingy(string Item)
{
fstream File; // Open the file, save the sorted words in it, and then close it.
File.open("Data/Alphabet.txt", ios::out | ios::in);
File << Item;
File.close();
}
void Alphabetical_Order(string Text_File)
{
fstream file;
file.open(Text_File); // Open the file that we are going to organize
std::set<std::string> sortedItems; // The variable that we will store the sorted words in
fstream words; // To see how many words are in the file
words.open(Text_File);
int Words = 0;
do
{
string word;
words >> word;
Words++;
} while (!words.eof());
for (int i = 1; i <= Words; ++i) // Set a loop to take the words out of the file and put them in our variable
{
std::string Data;
file >> Data;
Data = Data + " ";
sortedItems.insert(Data);
}
std::for_each(sortedItems.begin(), sortedItems.end(), thingy);
}
Does anyone know how to fix this?
When you open the fstream in thingy, try opening with ios::ate flag as well. This will allow you to append your text to the file, rather than rewrite every time you call the function.
That being said, you should not be opening and closing the file every time you call the function. Maybe pass a reference to a fstream that gets managed from outside the function thingy.
I hope this helps.
Aiden already pointed out the main problem in your code (+1).
For the records, I'd like however to propose you a more efficient output using the powerfull ostream_iterator: it avoids opening/closing the output file a lot of times and doesn't need trailing spaces in all strings. This being said, I'd suggest to void the unnecessary double pass read as well:
void Alphabetical_Order(string Text_File)
{
ifstream file(Text_File); // Open in read mode
std::string word;
std::set<std::string> sortedItems; // The variable that we will store the sorted words in
while (file >> word) { // just read the file in one pass
sortedItems.insert(word); // to populate the set
}
ofstream ofs("alphasorted.txt");
std::copy(sortedItems.begin(), sortedItems.end(), std::ostream_iterator<std::string>(ofs, " "));
}