• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
BaneTrapper

c++ file reading

16 posts in this topic

Hello.
I was using to read data from my files like this
[CODE]
/*text.txt*/
3
./Files/Maps/Map1.txt
./Files/Maps/Map2.txt
./Files/Maps/Map3.txt
[/CODE]
[CODE]
FILE* tempFile = fopen("text.txt", "r");
if(tempFile == NULL)
{
fclose(tempFile);
}
fscanf(tempFile, "%d", &MyInt);
for(int x = 0; x < MyInt; x++)
{
char tempChar[60];
fscanf(tempFile, "%s\n", tempChar);
MyVector.push_back(tempChar);
}
[/CODE]

But its really bugging me that i am limited to "char" cause the fscanf "%s" cant store to string.

What libraries can i use to read data from .txt files to string directly , and hopefully are simple to use
0

Share this post


Link to post
Share on other sites
I wouldn't use iostream. Something like this works for me. Imagine an input file like:

# a comment
a 3.5 3.5 yay_some_text
a 3.2 4.5 yay_some_more_text

[source lang="java"]FILE *pFile = fopen(filePath, "r"); // the file to load

char buffer[512]; // character buffer
char temp;
// read each line into the buffer
while (fgets(buffer, sizeof(buffer), pFile))
{
// switch based on leading type
switch (buffer[0])
{
case '#': // do nothing, it's a comment [img]http://public.gamedev.net//public/style_emoticons/default/biggrin.png[/img]
break;
case 'a':
// set ambient color ?
sscanf(buffer, "%c %f %f %s", &temp, &someFloat, &someOtherFloat, &aString);
break;
}


}[/source] Edited by Tudor Nita
-1

Share this post


Link to post
Share on other sites
Just personal preference I guess. It's a bit verbose for my liking and enforces type safety at compile time. This nags at me a bit too: [url="http://stackoverflow.com/questions/5164538/how-can-i-speed-up-line-by-line-reading-of-an-ascii-file-c/#answer-5165293."]http://stackoverflow...answer-5165293[/url]

Seeing how I'm really used to the fgets way, this is all, of course, highly subjective. Still, it's a valid alternative. Edited by Tudor Nita
0

Share this post


Link to post
Share on other sites
Two additional things: 1) the stdio API becomes just as verbose as iostreams, if not more so, when you actually do error handling. 2) your code doesn't actually address the OPs original complaint: not being able to work with string objects directly.
1

Share this post


Link to post
Share on other sites
[quote name='Tudor Nita' timestamp='1345463722' post='4971436']<br />This nags at me a bit too: http://stackoverflow...answer-5165293<br />[/quote]N.B. If you want to avoid the formatting overhead of fstream, you can shed one layer of abstraction by accessing it's internal filebuf object, though obviously you're now responsible for doing some of the work that the stream used to do for you.
1

Share this post


Link to post
Share on other sites
If this could help some then cool! However, since you're working in text files - let's say for instance you have:

[code]
Level TItle: The Doom Room
Models: 25
Textures: 1000
....
[/code]

if you're using fstream you can do:

[code]
char input;
fin = file.open("map1.txt");

fin.get(input);
while(input != ":") {
fin.get(input);
}

fin >> MapName;

fin.get(input);
while(input !=":") {
...
}

[/code]

This is just a suggestion what I used previously for my model file until I converted the file to binary. Just throwing it out there. My example is pretty straightforward and easy. I'm sure others may have preffered ways of reading a text file.
-1

Share this post


Link to post
Share on other sites
try with something like this.

a 3.5 3.5 yay_some_text
a 3.2 4.5 yay_some_more_text

[CODE]
ifstream f;
f.open(file);
char dat[256];
for(;;){
if(!f){
break
}
f >> dat;
if(strcmp(dat,"a") == 0){
float x, y;
char txt[256];
f >> x >> y >> txt;
}
}
[/CODE]
0

Share this post


Link to post
Share on other sites
[quote name='Exessuz' timestamp='1345749817' post='4972710']
try with something like this.

a 3.5 3.5 yay_some_text
a 3.2 4.5 yay_some_more_text

[CODE]
ifstream f;
f.open(file);
char dat[256];
for(;;){
if(!f){
break
}
f >> dat;
if(strcmp(dat,"a") == 0){
float x, y;
char txt[256];
f >> x >> y >> txt;
}
}
[/CODE]
[/quote]

That code risks causing a buffer overflow though, you could do: f >> setw(256) >> dat to ensure it doesn't happen when you read data. (or just use c++ strings)

strcmp is also potentially dangerous if dat isn't null terminated. (This is exactly why one should use the C++ string and stream objects rather than the C functions) Edited by SimonForsman
2

Share this post


Link to post
Share on other sites
[quote name='Tudor Nita' timestamp='1345463722' post='4971436']
This nags at me a bit too: [url="http://stackoverflow.com/questions/5164538/how-can-i-speed-up-line-by-line-reading-of-an-ascii-file-c/#answer-5165293."]http://stackoverflow...answer-5165293[/url]
[/quote]

Things to point out and quote from there would be:

"EDIT #2: I've found that the slow down for me was due to the set insert"

"Which gives a slowdown of a whooping 17%.
This takes into account:
automatic memory management (no buffer overflow)
automatic resources management (no risk to forget to close the file)
handling of locale"

Unless you deal with a huge text file, 17% are nothing compared to what you get in return and once you manually do the equivalent, chances are your own code would be as "slow" or even slower. Edited by Trienco
0

Share this post


Link to post
Share on other sites
Guess i should replay my fix ^^.
[CODE]

std::vector<string> MapList; //The vector where to hold what Maps to hold
int HowManyMaps = 0; //Keaping this for later
std::string tempString;

std::fstream tempStream("./Data/Map.txt");
if(tempStream.is_open)
{
tempStream >> HowManyMaps;
tempStream.ignore(2);
for(int a = 0; a < HowManyMaps; a++)
{
tempStream >> tempString;
tempStream.ignore(1);
MapList.push_back(tempString);
}
}
tempStream.close();

//Exit
for(int x = 0; x < HowManyMaps; x++)
{
MapList [x].clear(); //clear the strings
}
MapList.clear();
[/CODE]

only problem i got is that i can save file as "Text.gam" then open it with fstream as "Text.gam"
but if i open it with Notepad... It becomes "Text.gam.txt" file =,= so anoing Edited by BaneTrapper
0

Share this post


Link to post
Share on other sites
[quote name='BaneTrapper' timestamp='1345913927' post='4973277']
Guess i should replay my fix ^^.
[CODE]

std::vector<string> MapList; //The vector where to hold what Maps to hold
int HowManyMaps = 0; //Keaping this for later
std::string tempString;

std::fstream tempStream("./Data/Map.txt");
if(tempStream.is_open)
{
tempStream >> HowManyMaps;
tempStream.ignore(2);
for(int a = 0; a < HowManyMaps; a++)
{
tempStream >> tempString;
tempStream.ignore(1);
MapList.push_back(tempString);
}
}
tempStream.close();

//Exit
for(int x = 0; x < HowManyMaps; x++)
{
MapList [x].clear(); //clear the strings
}
MapList.clear();
[/CODE]
[/quote]
Some critiques:[list]
[*][url="http://www.cplusplus.com/reference/iostream/ifstream/is_open/"][font=courier new,courier,monospace]is_open[/font][/url] is a function, not a variable. You need parenthesis after it (right now, you're not actually calling it), like so: [font=courier new,courier,monospace]is_open()[/font]
[*]You should just use the function [url="http://www.cplusplus.com/reference/iostream/ios/good/"][font=courier new,courier,monospace]good()[/font][/url] instead of [font=courier new,courier,monospace]is_open()[/font], because [font=courier new,courier,monospace]good()[/font] will check for more errors than [font=courier new,courier,monospace]is_open()[/font].
[*]You don't need to manually close() the stream. It will close itself automatically when it goes out of scope. There's nothing wrong with closing it, of course, but it's not necessary.
[*]You don't need to manually clear() the strings or the vector. They will automatically be cleared and free their memory when they also go out of scope.
[*]What happens if you've got a corrupt file (or someone maliciously edits it) so that [font=courier new,courier,monospace]HowManyMaps[/font] is incorrect? If you're going to loop over all the elements in a vector, use the vector's [font=courier new,courier,monospace]size()[/font] member to make sure you don't go over/under bounds (but here in this case the entire iterating and clearing over the vector is unnecessary, as stated). Also, [font=courier new,courier,monospace]for(int a = 0; a < HowManyMaps; a++)[/font] should also be checking if the [font=courier new,courier,monospace]tempStream[/font] is still [font=courier new,courier,monospace]good()[/font], because it's possible you're trying to read more maps than the file has (if it's a corrupt/incorrect file), so it should be: [font=courier new,courier,monospace]for(int a = 0; a < HowManyMaps && tempStream.good(); a++)[/font]...
[/list]

The hard thing about C++ is that because things might "work," but it doesn't mean they're right.

[quote name='BaneTrapper' timestamp='1345913927' post='4973277']
only problem i got is that i can save file as "Text.gam" then open it with fstream as "Text.gam"
but if i open it with Notepad... It becomes "Text.gam.txt" file =,= so anoing
[/quote]
Ditch Notepad and get [url="http://notepad-plus-plus.org/"]Notepad++[/url]. It's infinitely better.
0

Share this post


Link to post
Share on other sites
When I don't care too much about speed, I handle that type of thing in distinct re-usable functions (from a lack of deep familiarity with proper stream usage).

In your case, I might do it like this:
[code]//Load the file into a single string.
std::string fileContents = LoadFileAsString("text.txt");


//Remove comments.
fileContents = String::RemoveComments(fileContents, "//");
fileContents = String::RemoveComments(fileContents, "/*", "*/");

//Seperate the string into lines; this also eliminates empty lines via a callback function.
StringList lines = String::Seperate(fileContents, '\n', RemoveEmptyLines);
if(lines.empty())
{
//The file (barring empty lines and comments) is empty!
//Handle the error.
}

//Get the first line.
int line = 0;
int numberOfFiles = StringToInt(lines[line++]); //You can also use lines.at() and catch the exception for malformed files.

if(lines.size() > (line + numberOfFiles))
{
//Malformed file. Not as many lines as promised by 'numberOfFiles'.
//Handle the error.
}

//Find the iterators to the range of files we want.
auto beginningOfFiles = (lines.begin() + line);
auto endOfFiles = (beginningOfFiles + numberOfFiles);

//Copy the range of elements to their own vector.
StringList files;
std::copy(beginningOfFiles, endOfFiles, files.begin());

//Continue processing the file...
line += numberOfFiles;

//...more file processing...[/code]

Most of those functions exist already exist in my code base through repeated needs, though RemoveComments() does not (I've never had to deal with multi-line comments before, but that's easy enough to solve - and once solved, becomes a permanent tool in your library, ready to use).

String::Seperate() function. Currently just takes a boolean to check for empty lines, but after writing this post I realize I need a callback function to check for non-empty but whitespace-filled lines. I also have it on my todo list (but as low priority) to make a version for if 'divider' is a single char (which would be alot faster).
StringList is just a typedef for [i]std::vector<std::string> [/i]since I use it so often.
[code]
//Divides up a string into multiple segments seperated by 'divider', and returns each segment in a StringList.
//If any segment is empty, and if 'ignoreEmptySegments' is true, the empty segments are not added to the StringList.
StringList Seperate(const std::string &str, const std::string &divider, bool ignoreEmptySegments)
{
StringList stringList;
//Check for empty string.
if(str.empty() || divider.empty())
return stringList;
size_t start = 0;
size_t end = str.find(divider, start);
//Keep looping, as long as there are more segments.
while(end != std::string::npos)
{
std::string subString = str.substr(start, end - start);
if(subString.size() > 0 || ignoreEmptySegments == false)
{
stringList.push_back(subString);
}
start = end + 1;
end = str.find(divider, start);
}
//Get the final (or the only) segment.
std::string subString = str.substr(start, str.size() - start);
if(subString.size() > 0 || ignoreEmptySegments == false)
{
stringList.push_back(subString);
}
return stringList;
}[/code]

LoadFileAsString() function.
[code]//Loads the entire file, newlines and all, and returns its contents as a string.
//Returns an empty string if the file doesn't exist.
std::string LoadFileAsString(const std::string &filename, ReadMode::Enum readMode)
{
//Open the file for reading.
std::ifstream file;
if(readMode == ReadMode::Binary)
file.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
else
file.open(filename.c_str(), std::ios_base::in);
if(!file)
{
Log::Message(MSG_SOURCE("FileFunctions", Log::Severity::Error)) << "Failed to load '" << Log_HighlightCyan(GetFilenameFromPath(filename)) << "' at " << Log_DisplayPath(filename)
<< "\nDo I have sufficient privileges? Does the file even exist?" << Log::FlushStream;
return "";
}
//Read the file into the stringStream.
std::ostringstream stringStream;
stringStream << file.rdbuf();
//Convert the stringStream into a regular string.
return stringStream.str();
}[/code]


Observant programmers will notice that most of my code suffers from [url="http://en.wikipedia.org/wiki/Schlemiel_the_Painter%27s_algorithm"][s]Shmuel[/s] Schlemiel the Painter algorithms[/url]. Many of the functions could be individually optimized, and the use of them together could further be optimized into a stand-alone function, like a "LoadFileAsStringList()" since I frequently go from File to String to StringList (easy enough to add).
I typically prefer clean code that works before I start optimizing code, and I don't do the actual optimizations until I find them necessary (otherwise I find myself wasting inordinate amounts of time of things that don't matter much). With file parsing, when I occasionally need files parsed fast, I load it as binary and don't bother with text parsing anyway. Edited by Servant of the Lord
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0