Reading from a text file (c++)

Started by
11 comments, last by AntonioR 12 years, 11 months ago
Hi, I need some help.

I want to be able to write some variable values in a text file and then read it from inside the application.

1.
Text file example :

window=0
screenwidth=800
screenheight=600
app_title=my project


So i want to read "window" and then its value, and then apply that value to appropriate variable inside the code.
Also I want to be able to read string or char values.

2.
I would also want to put more variables in the same row, and the read it one by one:
1 0 day month 1000 500
Advertisement
So which bit are you having a problem with? Reading from a file? Splitting it at the =? Determining whether it's a string or a char?

No-one here is going to just do it for you.

But as a start look into strings, iostream, and data structures.
Actually I wouldn't go that route (manually parsing using streams) for a configuration file. Find an existing configuration file library with a syntax that you like and just use that. INI files are strangely popular and so are XML files. There's also boost::program_options for a possibility.
For a quick and easy bit of string manipulation if you have access to boost I'd recommend looking at boost::split (within boost/algorithm/string.hpp).
- Teach a programmer an answer, he can code for a day. Show a programmer the documentation, he can code for a lifetime.
I just need it for some simple stuff, I don't want to use a whole new library for that.

I know something about iostream, I can read numbers like this.


ifstream filein("config.txt");
filein >> fullscreen >> SCREENW >> SCREENH ;


But the text file has just numbers inside so it won't be readable if I add some new stuff.

1
1024
768


So I guess
Splitting it at the =? Determining whether it's a string or a char?[/quote] is the actual problem.
If you are going to do it that way (roll your own), I think the basic process is:

1) read the line
2) find offset of '='
3) read before the '=' into a token variable
4) read behind the'=' into a value variable
5) switch on the token to assign the value variable to the correct program variable.
6) repeat with next line
I managed to find some code example, it works:

bool LoadSettings(int *Width, int *Height, int *Fullscreen)
{
FILE* fp;

char string[500];
fp = fopen("config.txt","r");

if (fp!=NULL)
{
char item[300];
char value[300];

while (fgets (string , 300 , fp)!=NULL)
{
//sscanf(string,"%s %[^\n]",&item, &value);
sscanf(string,"%s %s",&item, &value);

if (strcmp(item, "width")==0)
{
*Width = atoi(value);
}
else if (strcmp(item, "height")==0)
{
*Height = atoi(value);
}
else if (strcmp(item, "fullscreen")==0)
{
*Fullscreen = atoi(value);
}
}
}
else
{
return false;
}

}


Txt file:

width 1024
height 768
fullscreen 0
well, you could simply use

while (fgets (string , 300 , fp)!=NULL)
{
sscanf(string,"width %d",Width);
sscanf(string,"height %d",Height);
sscanf(string,"fullscreen %d",Fullscreen);
}


If the string is not matching, the variables won't be affected, so it can be simple as that. You can even check the return value of sscanf (look it up)

But that's C, not C++. I'm sure C++ has better methods
Here is what I have been using for awhile, it doesn't read everything at once, but you can continually check the file for various settings.
Feel free to use it or make one yourself based on this, Its a modified version from some tutorial I read about 5 years ago, sorry but I do not have the link :/

ReadConfig.h

//Read a specific variable from our config file and return its value
//This is our error logging class
#ifndef READCONFIG_OBJECT

#define READCONFIG_OBJECT

#include <winsock.h>
#include <stdio.h>
#include <io.h>
#include <FCNTL.H>
#include <iostream>
#include <fstream>
#include <string>
#include <list>
using namespace std;

#define MAX_STRING 255



int ReadConfigInt(char* Filename,char* Variable); //return -1 on fail, -2 on file not found
string ReadConfigString(const char* Filename,char* Variable); //returns NULL on failure

#endif


ReadConfig.cpp

//Read config
#include "stdafx.h"
#include "ReadConfig.h"

int ReadConfigInt(char* Filename,char* Variable)
{


char line[MAX_STRING];
memset(line,0,MAX_STRING);
ifstream myconfig(Filename);
if(!myconfig)//could not open file
{
return NULL; //-2 file not found
}

while(!myconfig.eof())
{

myconfig.getline(line, MAX_STRING); // delim defaults to '\n'
if(myconfig)
{
if(line[0] == '/') //we are skipping this line
{ // skip comment line
continue;
}
else
{


char *pointerchar = NULL;
char var[MAX_STRING] = {'\0'}; // variable name
char val[MAX_STRING] = {'\0'}; // value its set to
size_t length =0;
pointerchar = strchr(line, '\n'); // find our newline
if(pointerchar != NULL)
{
*pointerchar = '\0'; //change newline to null character
}
length = strlen(line);
pointerchar = strchr(line, '='); //find our equals character
if(pointerchar == NULL)
{
return NULL; //failure
} //Parse Error

memcpy(var, line, pointerchar - line);// get the part before the first =
pointerchar++;// skip the actual '=' sign
memcpy(val, pointerchar, (line+length)-pointerchar);// get the value of the var
if (strcmp(var,Variable)==0)//see if we found it
{
return atoi(val);
}
}

}

}

myconfig.close();


return NULL; //didnt find that variable
}



string ReadConfigString(const char* Filename,char* Variable)
{


char line[MAX_STRING];
memset(line,0,MAX_STRING);
ifstream myconfig(Filename);
if(!myconfig)//could not open file
{
return "Unknown";
}

while(!myconfig.eof())
{

myconfig.getline(line, MAX_STRING); // delim defaults to '\n'
if(myconfig)
{
if(line[0] == '/') //we are skipping this line
{ // skip comment line
continue;
}
else
{


char *pointerchar = NULL;
char var[MAX_STRING] = {'\0'}; // variable name
char val[MAX_STRING] = {'\0'}; // value its set to
size_t length =0;
pointerchar = strchr(line, '\n'); // find our newline
if(pointerchar != NULL)
{
*pointerchar = '\0'; //change newline to null character
}
length = strlen(line);
pointerchar = strchr(line, '='); //find our equals character
if(pointerchar == NULL)
{
return NULL;
} //Parse Error

memcpy(var, line, pointerchar - line);// get the part before the first =
pointerchar++;// skip the actual '=' sign
memcpy(val, pointerchar, (line+length)-pointerchar);// get the value of the var
if (strcmp(var,Variable)==0)//see if we found it
{
return val;
}
}

}

}

myconfig.close();


return NULL; //didnt find that variable
}
Doing the same in c++:

#include <string>
#include <fstream>

bool LoadSettings(int &Width, int &Height, int &Fullscreen)
{
std::ifstream file("config.txt");
if(!file.is_open())
{
return false;
}
std::string line;
while(std::getline(file, line))
{
std::stringstream stream(line);
std::string name;
int value;
if(stream >> name >> value)
{
if(name == "width")
{
Width = value;
}
else if(name == "height")
{
Height = value;
}
else if(name == "fullscreen")
{
Fullscreen = value;
}
else
{
std::cerr << "Unknown config name: " << name << '\n';
}
}
else
{
std::cerr << "Failed to parse line: " << line << '\n';
}
}
}

Note this also features more robust error checking. The code you posted fails to fclose() the file you fopen(), among other issues.

I would not recommend using yewbie's code, it is terrible.

This topic is closed to new replies.

Advertisement