Writing to an output file

advertisement
Input Files, Output Files, and String
Functions
Although much of the world's data is stored in databases, there are many times when a
database is not needed. In those cases, you can store your data in a single file.
File: a collection of data that is located in secondary memory (hard drive, flash drive,
CD/DVD, the "cloud", etc.).
Text File: a file that only contains ASCII characters (strings). The following control
characters may be included: tab, carriage return, line feed.
File operations:
 Read data from an existing file ("input")
 Write data to a new file ("output")
 Append data to an existing file ("output")
C# tries to simplify file handling by using stream objects.
Stream: an ordered collection of bytes (characters).
An input file is referred to as an input stream. To read data from an input file, create a
StreamReader object.
An output file is referred to as an output stream. To write data to an output file, create a
StreamWriter object.
Create a new XNA project called Files.
To use streams, add the following to the top of your program:
using System.IO;
2/9/2016
Document1
Page 1 of 7
Writing to an output file
An output file is created using a StreamWriter object.
To declare an output file:
StreamWriter outFile;
StreamWriter is the data type. It tells C# that we are creating an object that will be used to
write data to an output file. Put this in the declarations area of your program.
The identifier outFile is the name the programmer has chosen for this StreamWriter. There
is nothing special about it; it is a name that the programmer makes up. It follows the rules
for creating identifiers in C# and should describe the purpose of the file.
To open an output file:
This statement prepares the file for writing (called "opening" the file):
outFile = new StreamWriter(path);
The path is a string variable that identifies the file path and name.
Example
outFile = new StreamWriter("E:/Stuff/HighScore.txt");
Note that I used slashes (/) instead of backslashes (\) which is what is normally used in
Windows paths. In C#, it is legal to use either slashes or backslashes, but if you use
backslashes, you must remember to use two backslashes everywhere where you would
normally use one backslash. So the previous statement could also be written like this:
outFile = new StreamWriter("E:\\Stuff\\HighScore.txt");
There is another trick that allows the programmer to only put single backslashes, and that is
to put the "at" symbol (@) before the string, like this:
outFile = new StreamWriter(@"E:\Stuff\HighScore.txt");
Any of these three methods will work. However, it just seems cleaner to use regular
slashes.
If you only supply a file name and do not put any path information (which disk drive the file
is on, which folder(s) it is in), the file will automatically go in the bin/x86/debug folder of
your application. This is called a relative path and is the preferred method in this class. A
relative path is called so because its path information is relative to the location of the
program that is running. The advantage of using relative path names is that you can move
your program folder anywhere and all of the file names will still work! So when you hand in
a program that uses relative path names, I will be able to run the program on my computer
without any modifications.
This is an example of a relative file name (no drive letter or backslash at the beginning).
outFile = new StreamWriter("Output.txt");
The file Output.txt will be written to the bin/x86/debug folder.
2/9/2016
Document1
Page 2 of 7
Writing data using a StreamWriter
The Write and WriteLine methods are used to write data to an output file. They work
exactly the same way they work when using the Console object to write to the output
window.
Writing to a file
To write text to the output file without moving to a new line afterwards:
outFile.Write("String to write");
Subsequent output will appear on the same line as the "String to write".
To write a line of text to the output file and move to a new line afterwards:
outFile.WriteLine("String to write");
And if you have already written a line to the output file and just want to move to a new line:
outFile.WriteLine();
And, when you are done, close the file:
outFile.Close();
Closing a file causes any data left in a buffer to be written to the file and frees up any
system resources that the file is using.
Warning: If you do not close the output file, the last chunk of data in the buffer may not
get sent to the file! Some of your data will be missing!
2/9/2016
Document1
Page 3 of 7
Example
Here is a procedure that will write the numbers 1 to 1,000 to a file. It requires that the path
be sent to it as a parameter. Add this procedure to your game program and execute the
procedure when the user presses the "A" button on the game controller.
Here is code to call the Save procedure. It will save data in the default directory because no
path information is provided.
First, declare the file at the top of the program as a module-level variable:
StreamWriter outFile;
GamePadState gamePad, prevGamePad;
Then add code to see if it's time to write the data to the file in the Update procedure:
gamePad = GamePad.GetState(PlayerIndex.One);
if (gamePad.Buttons.A == ButtonState.Pressed &&
prevGamePad.Buttons.A == ButtonState.Released)
Save("junk.txt");
prevGamePad = gamePad;
Then add the Save procedure:
public void Save(String path)
{
StreamWriter outFile = new StreamWriter(path);
outFile.WriteLine("Data");
for (int i = 0; i < 1000; i++)
{
outFile.WriteLine(i.ToString());
}
outFile.Close();
}
Look at the output file when done. Then delete the output file and run the program again,
but comment out the outFile.Close() command. Take a look at the output file again. It will
be incomplete because you didn't close it!
2/9/2016
Document1
Page 4 of 7
Reading from an input file
An input file can be read by using a StreamReader object. To read from a file, we need a file to
read from. Create a sample data file in Notepad:
George
John
Thomas
James
Andrew
95
85
75
65
55
Save the file in the bin/x86/debug folder of your project. Call it HighScores.txt.
To declare an input file:
Declare it like this:
StreamReader inFile;
StreamReader is the data type. It tells C# that we are creating an object that will be used
to read data to from an input file.
The identifier inFile is the name the programmer has chosen for this StreamReader. It is a
name that the programmer makes up. It follows the rules for creating identifiers in C# and
should describe the purpose of the file.
To open an input file:
This statement prepares the file for reading (called "opening" the file):
inFile = new StreamReader(path);
The path is a string and must be a valid path name on the system that the program is
running on.
NOTE: There is nothing special about the name inFile. It is just the identifier that we chose for
our StreamReader object. We could have called it anything as long as we followed C#'s rules for
identifiers.
NOTE: If you want to use the file in more than one procedure, you need to make it a modulelevel variable (declare it at the top of the program).
Example
inFile = new StreamReader("E:/Stuff/HighScores.txt");
2/9/2016
Document1
Page 5 of 7
Reading data using a StreamReader
The Read and ReadLine methods are used to read data from an output file. They work
exactly the same way they work when using the Console object to read from the keyboard.
In this class, we will almost always use the ReadLine method.
Reading from a file
To read a line from the input file:
line = inFile.ReadLine();
where line must be a string variable. With text files, all of the data is string data.
Example
We are going to read the data from our data file into a pair of arrays. We will need the following
module-level variables. Add them to the declaration area of your program.
const int maxPlayers = 10;
// array size
int playerCount = 0;
// players read so far
string [] player;
// player names
int [] score;
// player scores
The arrays need to have memory allocated in the Initialize procedure. NOTE that the following
code does NOT work because we are re-declaring the variables! The module-level variables
never get initialized!
If we initialize them when we declare them, the declarations will look like this:
string [] player = new string [maxPlayers];
int [] score = new int [maxPlayers];
If you put the code to allocate memory for the array in Initialize, it will look like this:
player = new string [maxPlayers];
score = new int [maxPlayers];
We also need a signal to read the file. We will use a press of the "B" button. Add this code to
your Update method:
if (gamePad.Buttons.B == ButtonState.Pressed &&
prevGamePad.Buttons.B == ButtonState.Released)
Read("HighScores.txt");
2/9/2016
Document1
Page 6 of 7
NOTE: The following code assumes that there are at least maxPlayers lines in the output file.
Here is the code to read the file. Add this method to your program.
public void Read(string path)
{
string line;
inFile = new StreamReader(path);
for (int i = 0; i < maxPlayers; i++)
{
line = inFile.ReadLine();
//Get the line
player[playerCount] = line.Substring(0, 10);
score[playerCount] = Convert.ToInt32(line.Substring(10));
Console.WriteLine(player[playerCount] + " " +
score[playerCount]);
playerCount++;
}
Console.WriteLine("Players: " + playerCount);
}
Reading a file, Version 2
Another way to read the file might be to read one line every time the player clicks on the
button. There's no way to prevent the player from clicking on the button too many times. So we
need a way of knowing when we run out of data. Let's re-write our program to work like this.
public void Read()
{
string line;
line = inFile.ReadLine();
//Get the line
player[playerCount] = line.Substring(0, 10);
score[playerCount] = Convert.ToInt32(line.Substring(10));
Console.WriteLine(player[playerCount] + " " + [playerCount]);
playerCount++;
}
public void OpenFile(String path)
{
inFile = new StreamReader(path);
playerCount = 0;
}
To test for end of file
The StreamReader class has a built-in method called Peek which returns an integer. The
value of the integer will always be non-negative as long as more data is available in the file.
But it will return the value -1 when there is no more data available.
So we can solve our problem by testing for end of file before we read a new line.
if (inFile.Peek() >= 0)
{
// read from the file
}
2/9/2016
Document1
Page 7 of 7
Download