There's some code I wrote that should read all new lines in a text file, but it gets stuck on one of the loops it runs.
The code is as follows:
#define MAX_MESSAGE_LENGTH 200;
fstream("some/random/file.txt", ios::in | ios::out);
streampos fileSizeReference = 0;
vector<string> messages;
vector<string> onDisplay;
char message[MAX_MESSAGE_LENGTH];
if((int)fileSizeReference == 0)
fileReader.seekg(0);
else
fileReader.seekg((int)fileSizeReference + 1);
cout << "Test" << endl;
// Add all new messages to the messages vector
do
{
fileReader.getline(message, MAX_MESSAGE_LENGTH);
string newMsg = message;
messages.push_back(newMsg.substr(0, MAX_MESSAGE_LENGTH));
}
while (!fileReader.eof());
//
cout << "Test" << endl;
fileReader.seekg(0, ios::beg);
// Set the newest messages in the onDisplay vector
for(int i = 0; i < amountOfMessages; i++)
{
onDisplay[i] = messages[messages.size() - (i + 1)];
}
//
cout << "Test" << endl;
// Display new messages
int current_Y = 0;
for(int i = 0; i < amountOfMessages; i++)
{
current_Y = renderText(messages[i], current_Y);
}
//
// set the new file size as the fileSizeReference
fileReader.seekg(0, ios::end);
fileSizeReference = fileReader.tellg();
The text file looks like this:
Hello World!
Carpe Diem
Random Message
Whenever I run this code, I don't get past the first do-while loop.
This is the first run, so the fileSizeReference is 0.
The newMsg variable within the loop is always an empty string, just like the message array.
Does any one of you know why my code gets stuck?
Thank you in advance!
You have two errors (at least).
do
{
fileReader.getline(message, MAX_MESSAGE_LENGTH);
string newMsg = message;
messages.push_back(newMsg.substr(0, MAX_MESSAGE_LENGTH));
}
while (!fileReader.eof());
should be
while (fileReader.getline(message, MAX_MESSAGE_LENGTH))
{
string newMsg = message;
messages.push_back(newMsg.substr(0, MAX_MESSAGE_LENGTH));
}
More reading Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
Incidentally those two lines in the while loop can also be simplified, just this will work perfectly well.
messages.push_back(message);
And secondly after finishing reading the stream will be in an error state, which you need to clear before seeking back to the beginning of the file (closing and reopening the file would also work).
while (fileReader.getline(message, MAX_MESSAGE_LENGTH))
{
string newMsg = message;
messages.push_back(newMsg.substr(0, MAX_MESSAGE_LENGTH));
}
fileReader.clear();
fileReader.seekg(0, ios::beg);
Related
When I add a file to a char array, then print, I get garbage output (random ASCII symbols). The file contains only text (a paragraph).
The code is as follows:
int arraySize = 0;
string line;
while(getline(inFile, line)){
//cout << line << endl; // this will print array fine.
arraySize += line.length();
}
char message[arraySize];
char encrypted[arraySize];
//adds file to array
int i = 0;
while(inFile.good() && !inFile.eof()){
inFile.get(message[i]);
i++;
}
message[i] = '\0';
//prints array
for(int i = 0; i < arraySize; i++){
cout << message[i]; //this returns garbage values
}
I believe its printing garbage because it thinks there's nothing in the array messages, but I do not know why there is "nothing there."
The reason is you reached the end of file when you count the length of the text thus the read pointer is at the end of the file and you used it again to read the text file.
To do it: Get the read pointer again to the beginning:
inFile.clear();
inFile.seekg(0, ios::beg);
while(inFile.get(message[i])){
i++;
}
Also don't use: while (!infile.eof()) it is considered to be incorrect.
What I recommend is to use std::vector you don not mind about the file size or any allocation / de-allocation of memory. So your code can be like this:
std::ifstream inFile("data.txt"); // your file name here
std::string strLine;
std::vector<std::string> vecStr;
while(std::getline(inFile, strLine))
vecStr.push_back(strLine);
for(int i(0); i < vecStr.size(); i++)
std::cout << vecStr[i] << std::endl;
inFile.close();
Have you seen how the code is charm above?
NB: You got the garbage values because the array is only declared but not initialized:
The first read gets the length of the text. But moved the read pointer to the end and then you did:
while(inFile.good() && !inFile.eof()){ // Will fail because inFile.eof() is true from the previous read.
//std::cout << "Inside the reading loop" << std::endl;
inFile.get(message[i]);
i++;
}
As you can see above the loop will not be executed because the previous read reached the eof thus the array is just declared without being initialized thus as you know it contains garbage values.
To confirm that the loop is not executed un-comment the line above and see if the loop is executed. The result is no printing message which means it was not executed.
I have created a function to write some data on a text file, and it works fine. I created another function to read in all the content of the file, and print it out for me! But, it is not working for some reason. Could any one help please?
This is my function:
void myClass::displayFile() {
char line[LINE]; //to hold the current line
file.open("data.txt", ios::app);
//keep reading information from the file while the file is open and has data
while (!file.fail() && !file.eof()) {
int lineSize; //to loope through each line
file.getline(line, LINE);
lineSize = strlen(line);
//loop through the line to print it without delimiters
for (int i = 0; i < lineSize; ++i) {
if (line[i] == ';') {
cout << " || ";
} else {
cout << line[i];
}
}
}
file.close();
file.clear();
if (file.fail()) {
cerr << "Something went wrong with the file!";
}
}
Note: The function compiles and the loop is accessible, but the line string is empty.
This is the writing function:
void myClass::fileWriter() {
file.open("data.txt", ios::app);
file << name << ";" << age << ";" << "\n";
file.close();
file.clear();
}
Silly me, the cause of your problem was staring me right in the face from the beginning, and it's the app open-mode that's the problem. It is to open the file in write mode, which means you can't read from it.
And even if you could read from the file, the cursor is placed ad the end of the file the eofbit flag would have been set inside the first iteration anyway.
If you want to read from a file, then either use std::ifstream which automatically sets the in mode if you don't specify a mode, or you have to explicitly set the in mode when opening.
I have attached my full source code of my program that can open a .txt file. It doesn't execute after the cout << length. I am trying to store the .txt file information in memory by using an array.
#include <iostream>
#include <string.h>
#include <fstream>
using namespace std;
char filename[128];
char file[10][250];
int count;
int length;
string line;
int main ()
{
int count = 0;
int length = 0;
cout << "Filename: ";
cin.clear();
cin.getline(filename, sizeof(filename));
string new_inputfile(filename);
ifstream inputfiles (new_inputfile.c_str());
if(!inputfiles.is_open())
{
cout << "File could not be opened. \n ";
}
else
{
for (int i=0; getline(inputfiles,line); i++)
{
length++;
}
cout << length;
// char file[length][250]; <- How can I create the array based on the length variable?
// CODE DOES NOT EXECUTE AFTER THIS.
while(!inputfiles.eof() && (count<10))
{
inputfiles.getline(file[count],250);
count++;
}
for(int i=0; i < count; i++)
{
cout << file[i] << endl;
}
}
inputfiles.close();
return 0;
}
Also, since file[] is char, say for example file[1] contained the char Name=Mike, how do I strip off everything before the =. I want just Mike. I know with string, I can use substr() method, but I don't know for char.
This is horribly wasteful way to count number of lines in a file.
for (int i=0; getline(inputfiles,line); i++) // i is also completely useless here
{
length++;
}
You're reading the whole file only to throw everything away and start again! And after this loop is done, inputfiles.eof() will be true and you'll never enter neither the next while loop nor the last for loop (because i == count). Execution skips directly to inputfiles.close() and then you return from main.
I suggest you work on the line string as you go:
for ( ; getline(inputfiles, line); )
{
// do stuff with line and ditch the global char arrays
}
If you want store the lines for later, well, just save them :) The easiest thing to do is to use a vector:
std::vector<std::string> all_them_lines;
while (getline(file, line) all_them_lines.emplace_back(line);
There, the entire file is now saved in all_them_lines, line by line. You can access them just like you would in an array, like all_them_lines[0]. You also don't need to know the number of lines beforehand - vectors expand automatically when you add stuff to them.
Now to parse a line and extract formatted input from it, check out what stringstream class has to offer.
You asked:
// char file[length][250]; <- How can I create the array based on the length variable?
Declare file as:
char (*file)[250] = NULL;
and then,
file = new char[length][250];
Make sure you call delete [] file before the end of the function.
You said:
// CODE DOES NOT EXECUTE AFTER THIS.
You can rewind the stream and start reading from it again.
inputfiles.seekg(0);
count = 0;
while(!inputfiles.eof())
{
inputfiles.getline(file[count],250);
count++;
}
Answered:
changing
while (tracefile->good()){
getline(*tracefile,line);
....
to
while(getline(*tracefile, line)){
....
did the trick. Thank you, #pmr.
Original:
I made a cache simulator for my computer architecture class which is supposed to read in a trace file that contains memory instructions for my cache.
I used a test trace file with only 1000 lines when making the program, but the actual trace files are 50k+ lines. With the test trace, the program runs perfectly. With the actual trace, the program continues until it tries to use .substr() on a line, which causes an out_of_range exception and stops my program prematurely. I investigated and found that getline() is giving empty strings when the trace is too big. Remember, this does not happen on traces <= ~5000 lines.
Does anyone know why this is happening? I am using an ifstream if that matters.
EDIT: sorry here is the code. It doesn't get past the "...."
main:
cout << "Program started.\n";
string str[6];
int i = 0;
/* check for the correct number of arguments */
if(argc != 3){
cout<<"usage: "<< argv[0] <<" <configfile> <tracefile>\n";
exit(0);
}
string confname = argv[1];
string tracename = argv[2];
/* open the files and check if it worked */
ifstream confile;
ifstream tracefile;
confile.open (argv[1], ios::in);
if (!confile.is_open()){
cout<<"Could not open config file.\n";
exit(0);
}
if (confile.is_open()) cout << "Config file loaded.\n";
tracefile.open (argv[2], ios::in);
if (!tracefile.is_open()){
cout<<"Could not open trace file.\n";
exit(0);
}
if (tracefile.is_open()) cout << "Trace file loaded.\n";
/* read in the data from the config file */
if (confile.is_open()){
i = 0;
while(confile.good() && i != 6){
getline(confile, str[i]);
i++;
}
}
/* create the cache simulator */
cache csim(atoi(str[0].c_str()), atoi(str[1].c_str()),
atoi(str[2].c_str()), atoi(str[3].c_str()),
atoi(str[4].c_str()), atoi(str[5].c_str()));
cout << "Simulator started.\n";
/* send the simulator the trace */
csim.trace(&tracefile);
csim.trace:
cout << "Going through trace...";
int i;
string line;
string tag, index, offset;
this->IC = 0;
/* loop until there is no more lines */
while (tracefile->good()){
/* get the next line and increment the instruction counter */
getline(*tracefile,line);
this->IC++;
/* convert hex address to a binary address */
string address = "";
for (i = 0; i < line.substr(4,8).length (); i++)
{
....
It looks like one of your strings might not be long enough.
while (getline(*tracefile,line);){
/* get the next line and increment the instruction counter */
this->IC++;
/* convert hex address to a binary address */
//be sure to check length of string
if (line.size() < 12)
{
cerr << "line is too small" << endl;
continue;
}
string address = "";
string tmp_str = line.substr(4,8);
for (i = 0; i < tmp_str.size(); i++) //tmp_str.size() will always be 8
{
}
}
I've done this before, but can't find the sample code...still new to c++.
I need to output multiple lines to a text file. Right now it only outputs the last line, so I assume its overwriting the prior line each time the loop is run. How do I get it to output a line and then output to the next line, etc. without writing over the prior line?
Here's a snippet:
int main()
{
int n = 1;
while (n <= 100)
{
int argument = 0 + n;
ofstream textfile;
textfile.open ("textfile.txt");
textfile << argument << endl;
textfile.close();
++n;
}
return 0;
}
Open the file before you enter the loop, and close it after you exit the loop.
It looks like the default open mode is override, so it's only going to write over anything in the file previously with what is being currently written into the file.
Below are to keep the file handle open instead of reopening many times. If you want to append still you should use this :
textfile.open ("textfile.txt", ios::out | ios::app);
This will open the file for output and append on the end of the file.
int main()
{
int n = 1;
ofstream textfile;
textfile.open ("textfile.txt");
while (n <= 100)
{
int argument = 0 + n;
textfile << argument << endl;
++n;
}
textfile.close();
return 0;
}
You should open and close the file outside of the loop. When the file is opened, it defaults to overwriting. You can specify an append mode, but since opening a file is a somewhat lengthy operation, you don't really want to do that in this case.
Use this instead :
int main()
{
int n = 1;
while (n <= 100)
{
int argument = 0 + n;
ofstream textfile;
textfile.open ("textfile.txt", ofstream::out | ofstream::app);
textfile << argument << endl;
textfile.close();
++n;
}
return 0;
}