C++ Reading data from a file (containing spaces) line by line - c++

I'm programming a game on a board 9x9 (which is a char 9x9 array). I wrote a method that saves the current game state in a file going according to the scheme bellow:
board.plansza[0][0]
board.plansza[0][1]
board.plansza[0][2]
board.plansza[0][3]
(...)
*points in int*
(Where every line is just a one character/space/number)
Now I need a method that's gonna read this file and put the data back in the same kind of array (if someone decided to stop playing, saved the game and then wanted to continue from previous state) as well as the variable for points.
The problem is that some of the lines in a saved file are just a space (' ') and all the methods I've tried are failing to read it properly because of that.
The latest way I tried (and failed):
for (int i = 0; i < ROZMIAR; i++){
for (int j = 0; j < ROZMIAR; j++){
zapis << board.plansza[i][j] << endl;
}
}
zapis << user.pkt << endl;
How do I read a file line by line if some lines contain only a space (which I don't want to ignore)?

Use getline(), like this:
#include <fstream>
#include <string>
int main()
{
std::ifstream infile("thefile.txt");
std::string line;
char matrix[10][2];
int i = 0;
while(std::getline(infile, line))
{
std:cout << line << std::endl;
if(line .find_first_not_of(' ') != std::string::npos)
{
// There's a non-space.
matrix[i++][0] = line[0];
}
}
return 0;
}

Related

First letters being erased when reading from data file c++

Can someone please explain why only the first letters are being deleted when reading in from a data file but only on the 1/2/3 parts of the array and not the 0 part? (sorry really don't know how to explain it)(I'll only include part of what I am getting as well as data file)
What i get
GoogleyleSmith01#gmail.comyleman27ecurity question:White rabbit with a watch
Deviantartragonmaster27andalfthegreyNULL
What it's supposed to be
GoogleKyleSmith01#gmail.comKyleman27securityquestion:Whiterabbitwithawatch
DeviantartDragonmaster27GandalfthegreyNULL
And the original data file
Google;KyleSmith01#gmail.com;Kyleman27;security question:White rabbit with a watch;
Deviantart;Dragonmaster27;Gandalfthegrey; NULL;
I won't include all of the code as it shouldn't be relevant to this issue
#include<iostream>
#include <fstream>
#include <string>
#include <vector>
#include<sstream>
using namespace std;
const int NCOLS = 4;
const int NROWS = 10;
void description_and_options(string data[][NCOLS], int count[NCOLS]);
void available_options();
void view_line_data(int choice,string data[][NCOLS]);
int main()
{
ifstream file_name;//create the new file
string user_input_file;//the files name inputed by the user
int stringlength;
string read_in_array[NROWS][NCOLS];
string line;
int counter[10] = { 1,2,3,4,5,6,7,8,9,10 };
string user_option_choice;
string small_exit = "x";
string large_exit = "X";
int view_choice;
cout << "Enter the name of the input file: ";
cin >> user_input_file;
if (user_input_file.length() > 4)// check to see if its more than 4 in length
{
stringlength = user_input_file.length(); //saves length
if (user_input_file.substr(stringlength - 4, 4) == ".txt")//checks to see if its .dat
{
file_name.open(user_input_file.c_str());
if (file_name.fail())
{
cerr << "The file " << user_input_file << " failed to open.\n";//tells user if it fails
exit(1);
}
}
}
else
{
user_input_file += ".txt";//adds .dat to non .dat
file_name.open(user_input_file.c_str());
}
if (file_name.fail())
{
cout << "File failed to open" << endl;
system("PAUSE");
exit(1);
}
for (int row = 0; row <= 9; row++)
{
for (int col = 0; col < 4; col++)
{
if (getline(file_name, line, ';'))
{
file_name.ignore(1, '\n');
read_in_array[row][col] = line;
cout << read_in_array[row][col];
}
}
cout << endl;
}
//[updown][leftright]
file_name.close();
is there anyway to fix this without completely changing the code?
It is ignoring the first character because you tell it to
file_name.ignore(1, '\n');
Is going to ignore the first character in the stream after each call to getline. It looks like you are doing this because you think the ; in the file it still there. What you need to remember about getline is that it discards the delimiter you use. That means it will read until it finds a ; and then it tosses that ; out. This means you do not need to ignore it since it is no longer there.
Just removing the call to ignore is not enough to fix the issue though. Since you are trying to parse an entire line what we need to do is read the line into a stringstream and then call getline on the stream to get the individual parts. This is because just reading to ; is going to capture the newline.
A quick refactor of your code gives you something that should look like
for (int row = 0; row <= 9; row++)
{
std::string temp;
std::getline(file_name, temp)
std::stringstream ss(temp)
for (int col = 0; col < 4; col++)
{
if (getline(ss, line, ';'))
{
read_in_array[row][col] = line;
cout << read_in_array[row][col];
}
}
cout << endl;
}
You are using wrongly ifstream::ignore().
Extracts characters from the input sequence and discards them, until
either n characters have been extracted, or one compares equal to
delim.
file_name.ignore(1, '\n'); always dismiss the first letter. In your case, the first letter after ";" in line.
file_name.ignore(1, '\n'); will make the stream ignore one character from the input.
From reading your code:
For what you call "the 0 part", ignore is not called yet before the first getline in the loop.
For "parts 1/2/3", the ignore statement makes the stream skip the next character
For the remaining parts, there is either a space or a '\n' that was skipped so that the readable letter was not skipped.

Why is the next line not executing C++

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++;
}

How to read a txt file with characters (without spacing) and store into a 2D character array with 15x15 in visual c++?

I'm kind of a newbie in C++ programming.. My command prompt output is a big bulk (repeated) of the characters I have in my txt file. I create a 2d array map[15][15] and try to read the txt file. the reading part is ok but now I dunno how to put them in a 2D character array..
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
char map[15][15];
int alp = 0;
int i = 0;
int main()
{
ifstream in;
//string s;
in.open("city.txt");
if(!in.is_open())
{
cout << "File open error! " << endl;
}
else
{
while(!in.eof())
{
//getline(in, s);
in >> map[i];
i++;
alp++;
//if(in.eof()) break;
cout << map[i] << endl;
}
}
for(i = 0; i <= alp; i++)
{
cout << map[i];
}
in.close();
return 0;
}
eof() will only return true only after the first failed read operation. That operation will not be caught by your code. You could have a test for eof directly after the read and then break if eof(), but that's not elegant:
IO operations on streams return a ref to the given stream. Streams have a meaningful conversion to bool. True indicates that the read was successful, e.g. eof wasn't reached yet, and the read target contains a new correct input value. The idiomatic way of using this feature is "while(in >> map[i])".
As to the algorithm: You say that there are no spaces and I assume it's all ascii chars, so it boils down to double looping over the array's lines and columns with two for loops. Inside those loops would be a line reading each character explicitly with get() like
if(!cin.get(map[i][j])) {/* unexpected eof/io error, abort or whatever */ }
As the data is textual, and separated into lines, I suggest you read directly into the sub-array using e.g. std:istream::getline:
for (size_t i = 0; in.getline(map[i], 15); ++i)
;

Best method for reading row and col of txt file

Sorry, im a C++ noob! I have looked around for a solution but cant seem to find one that best suits my need. I am tring to read the width(max amount of char in line) and height (max amount of lines per file) of a txt file. Planning on using varaibles to help make dynamic sized txt files/levels.
I have had fixed width and height working previous to this!
TXT FILE: Simple output of chars for room layout (space=floor, #=wall, X=door):
########
# #
# X
# #
########
PROBLEM: Thought this to be a simple problem, but it only reads 2 of each variable(hNum,wNum)before breaking loop and program cant continue.
-What am i doing wrong?
-Should i be using seekg or different loop somehow?
-Do i need to alter my vector to 2D vector?
-Which is the best method for achieving this?
Room.cpp
//LOAD CURRENT ROOM FROM FILE
ss << RoomNo;
string str = ss.str();
string fname = ("Room");
fname.append(str);
fname.append(".txt");
infile.open(fname);
infile.clear();
infile.seekg(0);
if(infile.is_open())
{
// Sets width and height depndant on txt file size
string line;
//NOT WORKING!
while( !infile.eof())
{
hNum++;
getline ( infile, line);
wNum += line.length();
break;
}
height=hNum;
width=wNum;
//END
// Loop to end of file- to get you all the lines from txt file.
while(!infile.eof())
{
int i;
for(int row = 0; row < width; row++)
{
infile.getline(RoomFile, 256);
i = 0;
for(int col = 0; col < height; col++)
{
data.push_back(RoomFile[i]);
i++;
}
}
}
}
else
{
cout << "ERROR: infile not open" << endl;
}
infile.close();
UPDATE
This is what i got, tryin to do what Sky suggested...but cudnt work it all out. Then steped thro and thought the loop wasnt active so altered the argument. Now getting runtime error!
PROBLEM: Expression: vector subscript out of range!
Suggestions anyone?
string line;
while(getline(infile,line))
{
getline(infile, line);
tempVector.push_back(line);
}
width=line.length();
height=tempVector.size();
A possible way that can work would be to create a vector of strings and read the entire file, with each line a string in the vector.
Rough example:
#include <vector>
#include <string>
#include <fstream>
/* ... */
vector<string> content;
string buffer;
while(!infile.eof())
{
getline(infile, &string, '/n');
content.push_back(string);
}
width = findMaxLengthOfStrings(content);
height = content.size();
You are reading each line of the file as a separate string. The strings are pushed onto the vector. You can then easily find which string in the vector is longest, by iterating through the vector, using size(). The length in lines of the file is obtained with size() on the vector itself.
Also, posting just the relevant parts of the code, the I/O function, would have helped. Just saying ;) A small screen size and such.

c++ how to build a 2D matrix of strings from a .dat file? 5 columns x rows

I need to read a .dat file which looks like this:
Atask1 Atask2 Atask3 Atask4 Atask5
Btask1 Btask2 Btask3 Btask4 Btask5
Ctask1 Ctask2 Ctask3 Ctask4 Ctask5
Dtask1 Dtask2 Dtask3 Dtask4 Dtask5
and i need to be able to output information like this:
cout << line(3) << endl; // required output shown below
>>Ctask1 Ctask2 Ctask3 Ctask4 Ctask5
cout << line(2)(4) << endl; // required output shown below
>>Btask4
I don't know how to read 1 line and split it into an array of 5 different strings.
I'd ideally like to have the whole .dat file converted into a vector or a list or some kind of matrix/array structure for easy reference
any simple code or solutions for this??
PLEASE HELP?!?!?!? :-)
EDIT:
vector<string> dutyVec[5];
dut1.open(dutyFILE);
if( !dut1.is_open() ){
cout << "Can't open file " << dutyFILE << endl;
exit(1);
}
if(dut1.eof()){
cout << "Empty file - no duties" << endl;
exit(1);
}
while ( !dut1.eof()){
int count = 0;
getline(dut1, dutyVec[count]);
count++;
}
Your problem addresses a number of issues, all of which I will attempt to answer in one go. So, forgive the length of this post.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <fstream>
int main(int argc, char argv[]){
std::vector <std::string> v;//just a temporary string vector to store each line
std::ifstream ifile;
ifile.open("C://sample.txt");//this is the location of your text file (windows)
//check to see that the file was opened correctly
if(ifile.is_open()) {
//while the end of file character has not been read, do the following:
while(!ifile.eof()) {
std::string temp;//just a temporary string
getline(ifile, temp);//this gets all the text up to the newline character
v.push_back(temp);//add the line to the temporary string vector
}
ifile.close();//close the file
}
//this is the vector that will contain all the tokens that
//can be accessed via tokens[line-number][[position-number]
std::vector < std::vector<std::string> > tokens(v.size());//initialize it to be the size of the temporary string vector
//iterate over the tokens vector and fill it with data
for (int i=0; i<v.size(); i++) {
//tokenize the string here:
//by using an input stringstream
//see here: http://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g
std::istringstream f(v[i].c_str());
std::string temp;
while(std::getline(f, temp, ' ')) {
tokens[i].push_back(temp);//now tokens is completely filled with all the information from the file
}
}
//at this point, the tokens vector has been filled with the information
//now you can actually use it like you wanted:
//tokens[line-number][[position-number]
//let's test it below:
//let's see that the information is correct
for (int i=0; i<tokens.size(); i++) {
for(int j=0; j<tokens[i].size(); j++) {
std::cout << tokens[i][j] << ' ';
}
std::cout << std::endl;
}
system("pause");//only true if you use windows. (shudder)
return 0;
}
Note, I did not use iterators, which would have been beneficial here. But, that's something I think you can attempt for yourself.