We have come quite far now in our File IO, having made a fully workable program based off reading files - but we still aren't done! Today we are going to take another step forward and start looking at the fstream class, which allows both reading and writing. Furthermore, we are going to finally take a look at the bit-flags, before next week when we move on with reading and writing data structures. Finally, in the week after that, we will complete this tutorial series by creating a ToDo list program using everything we have learned!
So without further ado, here is part 4 of my tutorial for File IO in C++!
Monday, May 13, 2013
File IO in C++ Part 4 [Tutorial]
Monday, April 29, 2013
Straying Off-Topic Again
My birthday has come around again, which usually calls for me to think back to how I spent the last year of my life. While this usually means contemplating some of the major discussions I've made of the past year, I've realized I could also apply some analysis to CollegeGameDev. And so when I start looking back over the past few months posts, I have become very off-topic, for better or for worse.
Labels:
Game Design,
My Life and Off-Topic
| Reactions: |
Monday, April 15, 2013
File IO in C++ Part 3 [Tutorial]
Over the past two weeks, we have worked through opening, closing, reading, and writing files. This tutorial will now show how these concepts can be put to use in order to make a simple flash-card like program. Furthermore, this program will highlight the need for more dynamic uses of the fstream class in order to ease data storage and retrevial.
Here it is, part 3 of my tutorial for File IO in C++!
Our questions will reside in a struct for them, and we will keep track of the number of questions and filename in respective variables. At the moment, this means we roughly have something that looks like:
There we go, making progress! Lets start things from the bottom up, working through the write functions back to the load functions.
There are a few things to take note of in here during our write step:
Creating a question is easy - First we prompt the user for input using cout. Then, we use the cin.getline(char, int) function in order to capture the input. It is important to note here that the char pointers in question[numQuestions] are uninitialized, thus we need to initialize them for the getline() function to work.
At the end of this function, we just update the numQuestions variable and write out the new file with the extra question.
firstTimePopulate() is going to be our last function here, and all it does is expand on the createNewQuestion() function. It looks like this:
With loadQuestions() being the most vital, and the most difficult, lets work on it first:
So, what is this big confusing function? Well, lets pay attention to a few things:
Also now that our questions have been loaded, displaying a question is just a matter of outputting 2 lines. cin.get() is used to force the user to get the next line, essentially flipping a card. Here's displayQuestion(int questionNumber):
Displaying all the questions in a file works quite similarly, just using a for loop to ensure each question is read. Instead of this being a flashcard like flip, we are going to just stream them out at once for reference:
This shouldn't be too bad to figure out - We get an input for file name, load our questions, then loop through a menu executing the choices based off of our six functions!
So, its done - Wrap it all together and there we go! Try experimenting with this code to get a feel for it, and make sure you understand the basics. Next week we will look at a much simpler way of writing/reading data structures (then line by line), and also examine the fstream class!
Here is the full code posting (and here is a link to this code on Github)
Here it is, part 3 of my tutorial for File IO in C++!
File IO in C++ Part 3
The Flash-Card Program
Overview
In the first week, we covered what a file is, and the basics of writing to a file. In week two, we examined reading from a file, and completed a simple program to read and write text from a file. This week we are going to build on those concepts to create a simple program that will do 4 things:- Load a text file containing up to 100 questions and answers.
- Display all the questions/answer combos inside the file.
- Display individual question/answer combos from the file.
- Allow the user to add questions to the file.
- Allow the file to be saved.
Prototypes and Structures
Now that we know what we want our program to do, lets create some prototypes for each of these functions. We will need:- A loadQuestions() function for loading the text file.
- A displayAllQuestions() function for displaying all the questions.
- A displayQuestion(int) function for displaying a singular question.
- A createNewQuestion() function for adding a question. Were also going to want a firstTimePopulate() method for adding questions to a blank file.
- A writeQuestions() function for saving to the text file.
Our questions will reside in a struct for them, and we will keep track of the number of questions and filename in respective variables. At the moment, this means we roughly have something that looks like:
//Load and Display Functions
void loadQuestions();
void displayQuestion(int);
void displayAllQuestions();
//Write and Create Functions
void firstTimePopulate();
void createNewQuestion();
void writeQuestions();
//Global Variables
struct Question{
char *question;
char *answer;
} questions[100];
char * fileName;
int numQuestions;
There we go, making progress! Lets start things from the bottom up, working through the write functions back to the load functions.
Write and Create Functions
As you can see, the first thing we have is writeQuestions(). This function is meant to output all of our questions into the text file specified at fileName. We are going to accomplish this following our 4 step strategy, Instantiate, Open, Write, Close - Let's see how this works out:void writeQuestions(){
ofstream writeFile; //Step 1 - Instantiate
writeFile.open(fileName); //Step 2 - Open
int i = 0; //Step 3 - Write
while (i < numQuestions){//*
if (*questions[i].question != '\0'){ //**
writeFile<<questions[i].question<<"\n";
writeFile<<questions[i].answer<<"\n";
}
i++;
}
writeFile.close(); //Step 4 - Close
}
There are a few things to take note of in here during our write step:
- * = Since questions is an array, we keep track of the number of used elements in numQuestions. Thus, when we write from questions, we need to check that we aren't writing unfilled elements, so we do a loop to ensure this doesn't happen.
- ** = Since we have the potential to accidentally write a blank question into the database, but there would be no sense keeping it, we filter out and skip writing any questions that have the '\0' character as their content ( meaning empty line).
void createNewQuestion(){
cout<<"What would you like your question to be?"<<endl;
cin.getline(questions[numQuestions].question = new char[128], 128);
cout<<"What would you like your answer to be?"<<endl;
cin.getline(questions[numQuestions].answer = new char[128], 128);
numQuestions++;
writeQuestions();
}
Creating a question is easy - First we prompt the user for input using cout. Then, we use the cin.getline(char, int) function in order to capture the input. It is important to note here that the char pointers in question[numQuestions] are uninitialized, thus we need to initialize them for the getline() function to work.
At the end of this function, we just update the numQuestions variable and write out the new file with the extra question.
firstTimePopulate() is going to be our last function here, and all it does is expand on the createNewQuestion() function. It looks like this:
void firstTimePopulate(){
cout<<"It looks like you have zero questions in your question file!"<<endl;
cout<<"Lets add a new question..."<<endl;
createNewQuestion();
}
Reading and Display Functions
So with writing out of the way, lets tackle our 3 read functions: loadQuestions(), displayQuestion(), and displayAllQuestions().With loadQuestions() being the most vital, and the most difficult, lets work on it first:
void loadQuestions(){
ifstream readFile; //Step 1 - Instantiate
readFile.open(fileName); //Step 2 - Open
if (readFile.is_open() == false){ //* - This means the file was just created, and that it never existed!
readFile.close(); //We wont be reading anything, so skip step 3 and do step 4 - close
numQuestions = 0; //Set Number of Questions to 0
firstTimePopulate(); //Create a new Question (which will inc numQuestions once)
return;
}
//Step 3 - Read
numQuestions = 0; //We do not know how many questions we will read, so lets assume its 0
while(!readFile.eof() && numQuestions < 100){ //We cant read past eof, and our question array is only 100 elements
readFile.getline(questions[numQuestions].question = new char[128], 128);
readFile.getline(questions[numQuestions].answer = new char[128], 128);
if (*questions[numQuestions].question != '\0') //** - If this loaded question is not empty, add it
numQuestions++;
}
readFile.close(); //Step 4 - Close
}
So, what is this big confusing function? Well, lets pay attention to a few things:
- We keep our 4 step structure, Instantiate, Open, Read, Close
- At *, we correct for the fact that the file may not exist - in this case, it did not open, so the is_open() call will allow us to correct for this... how? By creating a question inside of it of course!
- At step 3, we read through the file getting data from each line. Just like in the create functions, we need to ensure we create space for question[x]'s pointers.
- At **, we check to see if the question loaded actually has any content by comparing it with '\0'. If its blank, then we skip incrementing numQuestions, causing the next read to overwrite the current question.
- There is a potential memory leak in here, but its not too big of deal so long as loadQuestions() is only called at the start of the program.
Also now that our questions have been loaded, displaying a question is just a matter of outputting 2 lines. cin.get() is used to force the user to get the next line, essentially flipping a card. Here's displayQuestion(int questionNumber):
void displayQuestion(int questionNumber){
cout<<"Q: "<<questions[questionNumber].question<<endl;
cin.get();
cout<<"A: "<<questions[questionNumber].answer<<endl;
cin.get();
}
Displaying all the questions in a file works quite similarly, just using a for loop to ensure each question is read. Instead of this being a flashcard like flip, we are going to just stream them out at once for reference:
void displayAllQuestions(){
cout<<"Questions in "<<fileName<<endl;
for (int i = 0; i < numQuestions; i++){
cout<<"Q: "<<questions[i].question<<endl;
cout<<"A: "<<questions[i].answer<<endl<<endl;
}
}
Main
Lets put our code to use now by creating a main that allows us a looping menu to decide what to do with it all!int main() {
cout<<"Specify your questions file:";
cin.getline(fileName = new char[128], 128);
loadQuestions();
int choice;
while(choice != 4){
cout<<"\n\nWhat would you like to do?\n"
"0. Display All Questions\n"
"1. Add Questions\n"
"2. Ask 10 Questions\n"
"3. Questions File Info\n"
"4. Exit"<<endl;
cin>>choice;
cin.get();
if (choice == 0){
displayAllQuestions();
} else if (choice == 1){
createNewQuestion();
} else if (choice == 2){
for (int reps = 0; reps < 10; reps++)
displayQuestion(rand() % numQuestions);
} else if (choice == 3)
cout<<"You have "<<numQuestions<<" questions in your file "<<fileName<<endl;
}
cout<<"Exiting...";
return 0;
}
This shouldn't be too bad to figure out - We get an input for file name, load our questions, then loop through a menu executing the choices based off of our six functions!
So, its done - Wrap it all together and there we go! Try experimenting with this code to get a feel for it, and make sure you understand the basics. Next week we will look at a much simpler way of writing/reading data structures (then line by line), and also examine the fstream class!
Here is the full code posting (and here is a link to this code on Github)
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
using namespace std;
//Load and Display Functions
void loadQuestions();
void displayQuestion(int);
void displayAllQuestions();
//Write and Create Functions
void firstTimePopulate();
void createNewQuestion();
void writeQuestions();
//Global Variables
struct Question{
char *question;
char *answer;
} questions[100];
char * fileName;
int numQuestions;
int main() {
cout<<"Specify your questions file:";
cin.getline(fileName = new char[128], 128);
loadQuestions();
int choice;
while(choice != 4){
cout<<"\n\nWhat would you like to do?\n"
"0. Display All Questions\n"
"1. Add Questions\n"
"2. Ask 10 Questions\n"
"3. Questions File Info\n"
"4. Exit"<<endl;
cin>>choice;
cin.get();
if (choice == 0){
displayAllQuestions();
} else if (choice == 1){
createNewQuestion();
} else if (choice == 2){
for (int reps = 0; reps < 10; reps++)
displayQuestion(rand() % numQuestions);
} else if (choice == 3)
cout<<"You have "<<numQuestions<<" questions in your file "<<fileName<<endl;
}
cout<<"Exiting...";
return 0;
}
void loadQuestions(){
ifstream readFile;
readFile.open(fileName);
if (readFile.is_open() == false){
readFile.close();
numQuestions = 0;
firstTimePopulate();
return;
}
numQuestions = 0;
while(!readFile.eof() && numQuestions < 100){
readFile.getline(questions[numQuestions].question = new char[128], 128);
readFile.getline(questions[numQuestions].answer = new char[128], 128);
if (*questions[numQuestions].question != '\0')
numQuestions++;
}
readFile.close();
}
void displayQuestion(int questionNumber){
cout<<"Q: "<<questions[questionNumber].question<<endl;
cin.get();
cout<<"A: "<<questions[questionNumber].answer<<endl;
cin.get();
}
void displayAllQuestions(){
cout<<"Questions in "<<fileName<<endl;
for (int i = 0; i < numQuestions; i++){
cout<<"Q: "<<questions[i].question<<endl;
cout<<"A: "<<questions[i].answer<<endl<<endl;
}
}
void firstTimePopulate(){
cout<<"It looks like you have zero questions in your question file!"<<endl;
cout<<"Lets add a new question..."<<endl;
createNewQuestion();
}
void createNewQuestion(){
cout<<"What would you like your question to be?"<<endl;
cin.getline(questions[numQuestions].question = new char[128], 128);
cout<<"What would you like your answer to be?"<<endl;
cin.getline(questions[numQuestions].answer = new char[128], 128);
numQuestions++;
writeQuestions();
}
void writeQuestions(){
ofstream writeFile;
writeFile.open(fileName);
int i = 0;
while (i < numQuestions){
if (*questions[i].question != '\0'){
writeFile<<questions[i].question<<"\n";
writeFile<<questions[i].answer<<"\n";
}
i++;
}
writeFile.close();
}
Monday, April 1, 2013
1 Week File IO Tutorial Hiatus & Offtopic
I usually like to be consistent on pushing out updates, but this week I think I need a break due to school. As the semester draws near to the midway point, things pick up and get busy for me, keeping me from being able to take the time to polish content. Fortunately, this means spring break is coming too, which will give me a good chance to update some more posts!
Also, some advice on the subject of per-queuing posts: I try to avoid doing it, but I still think its far favorable to pre-queue (write posts and schedule them) then to post-post (posting posts after a date with a false time stamp). While both technically are a form of taking a break/being lazy, I feel like post-posts are more a form of cheating and "faking" then pre-queues are...
Either way, over time I have come to develop my own method which I think works out very nicely - I create very rough drafts of enough posts to cover me for a while, then periodically update each post and polish it in time for my next scheduled post. Through this, I can have consistent updates regardless of my school work, while largely avoiding pre-queues. This also enables me to make random, short posts as frequently, such as covering a large assignment that I wanted to share or to an update to a project, without having to worry about the quality of my content taking a dive.
More content next week, including a continuation of my tutorial series on C++!
Also, some advice on the subject of per-queuing posts: I try to avoid doing it, but I still think its far favorable to pre-queue (write posts and schedule them) then to post-post (posting posts after a date with a false time stamp). While both technically are a form of taking a break/being lazy, I feel like post-posts are more a form of cheating and "faking" then pre-queues are...
Either way, over time I have come to develop my own method which I think works out very nicely - I create very rough drafts of enough posts to cover me for a while, then periodically update each post and polish it in time for my next scheduled post. Through this, I can have consistent updates regardless of my school work, while largely avoiding pre-queues. This also enables me to make random, short posts as frequently, such as covering a large assignment that I wanted to share or to an update to a project, without having to worry about the quality of my content taking a dive.
More content next week, including a continuation of my tutorial series on C++!
Labels:
My Life and Off-Topic
| Reactions: |
Monday, March 18, 2013
File IO in C++ Part 2 [Tutorial]
Last week we worked on loading content from files, and this week we will now focus on reading content. After the completion of this tutorial, we will be ready to move on to advanced topics such as applying read/writes to make simple programs and eventually loading data structures with them.
For now, here is Part 2 of my tutorial for File IO in C++!
Monday, March 4, 2013
File IO in C++ Part 1 [Tutorial]
During my Introduction Classes (in Scheme and Java), file input and output was barely touched on. We learned the absolute basics of writing to files, but never anything in-depth (like strategies to load a large amount of data out of a file). For me and my game-making aspirations, this knowledge was a necessity, forcing me to learn File IO in Android and Java on my own. Recently I ran into the problem of File IO in C++, and I realized this could be a great time to write a quick tutorial on loading files. I asked my friends for common questions about File IO, and put together a list of what really needs answering.
Here is Part 1 of my tutorial for File IO in C++!
Here is Part 1 of my tutorial for File IO in C++!
Monday, February 18, 2013
How To Post Code Snippets on Blogger [Tutorial]
Here's a quicky post for this week about putting code snippets into HTML.
The largest problem with blogger is that it will not save code formatting correctly, and this is exacerbated by template fonts and a poor quotation system. In the end, most code suffers, which encourages its posting on a site such as Github.
However, when code is posted on GitHub, it's details are obviously not indexed by the webpage, harming the SEO ranking of the page. Furthermore, tutorials are nearly useless if there isn't code to review, which counts them out of the picture.
So, I wanted to find a code-formatting HTML line that would allow me to place code inside of my pages for tutorials. I figured at the end I could link to a syntax-highlighted gist, giving the best of both worlds. Here is what I wound up with...
The largest problem with blogger is that it will not save code formatting correctly, and this is exacerbated by template fonts and a poor quotation system. In the end, most code suffers, which encourages its posting on a site such as Github.
However, when code is posted on GitHub, it's details are obviously not indexed by the webpage, harming the SEO ranking of the page. Furthermore, tutorials are nearly useless if there isn't code to review, which counts them out of the picture.
So, I wanted to find a code-formatting HTML line that would allow me to place code inside of my pages for tutorials. I figured at the end I could link to a syntax-highlighted gist, giving the best of both worlds. Here is what I wound up with...
Labels:
Code Tutorials,
Website Tutorials
| Reactions: |
Subscribe to:
Posts (Atom)