You already know how to use the ReadLine and WriteLine functions for Console. With a bit more setup you can use similar syntax for files. Miles has a good basic introduction, page 71, section 3.6. Read it.
A couple of comments:
Files are objects, like arrays, and use the new syntax to create a new one.
The last piece of example code in Miles 3.6 is correct, but verbose. It has the condition:
(reader.EndOfStream == false)
Shorter (and not suggesting you are a newbie):
(!reader.EndOfStream)
We are not sure why Miles first declared an input file, reader, as a TextReader rather than a StreamReader. In later discussion of inheritance, we will see more about how one type of object can be declared as another.
Without comment Miles switches in the EndOfStream testing to declaring reader as a StreamReader, which has more capacities than a TextReader: In particular it has the property EndOfStream. The simpler thing would be to us a StreamReader declaration consistently.
Also you could declare reader using the more compact syntax with var:
var reader = new StreamReader("test.txt");
You can use var in place of a declared type to shorten your code with a couple of restrictions:
You could have used this syntax long ago, but as the type names become longer, it is more useful!
Things to note about reading from files:
If you just want the whole file read in at once as a single (multiline) string, use the StreamReader method ReadToEnd:
var reader new StreamReader("someFile.txt");
string wholeFile = reader.ReadToEnd();
reader.close();
We have summed the numbers from 1 to n. In that case we generated the next number i automatically using i++. We coud also read numbers from a file containing one number per line (plus possible white space):
static int CalcSum(string filename)
{
int sum = 0;
var reader = new StreamReader(filename);
while (!reader.EndOfStream) {
string sVal = reader.ReadLine().Trim();
sum += int.Parse(sVal);
}
reader.Close();
return sum;
}
Below and in project Files/SumFile/SumFile.cs is a more elaborate, complete example, that also skips lines that contain only whitespace. Main takes a command line parameter containing the filename, and it gives several checks and warning messages.
using System;
using System.IO;
namespace Files
{
class SumFile
{
public static void Main(string[] args)
{
if (args.Length == 0){
Console.WriteLine(
"Expect on command line: a file name for a file of integers!");
}
else if (File.Exists(args[0])) {
Console.WriteLine("The sum is {0}", CalcSum(args[0]));
}
else {
Console.WriteLine("Bad file name {0}", args[0]);
}
}
/** Read the named file and
* print the sum of an int from each line
* that is not just white space. */
static int CalcSum(string filename)
{
int sum = 0;
var reader = new StreamReader(filename);
while (!reader.EndOfStream) {
string sVal = reader.ReadLine().Trim();
if (sVal.Length > 0) {
sum += int.Parse(sVal);
}
}
reader.Close();
return sum;
}
}
}
A useful function used in Main for avoiding filename typo errors is in the System.IO namespace
bool File.Exists(string filenamePath)
It is true if the filename exists.
See Setting the Working Directory and Command Line Arguments in MonoDevelop for testing SumFile.cs inside MonoDevelop.
Warning
If you are using files with MonoDevelop, note that the default directory to start from when running a program, is the subdirectory bin/Debug. We will keep data files in the main project directory. To avoid needing directory path names with test data, you need to make sure the working directory matches the test data location.
Before you run your program:
Later when running your program:
You can add a text data file as a part of your project in your project directory by File ‣ New ‣ File, bringing up the New File dialog. Select Misc on the left column and then Empty Text File in the next column, and enter the file name.
You can test all of this with the project Files/SumFile. There is a test file in the project directory numbers.txt. You could make a custom run mode using the command line parameter examples.txt and setting the working directory to the project directory SumFile. You might want to copy the project to your repository. open it in MonoDevelop, add a new data file, and use that as a command line parameter.
Here is a simple example copying a file line by line to a new file in upper case:
var reader = new StreamReader("Text.txt");
var writer = new StreamWriter("UpperText.txt");
while (!reader.EndOfStream) {
string line = reader.ReadLine();
writer.WriteLine(line.ToUpper());
}
reader.Close();
writer.Close();
You can try this in csharp:
First create a Text.txt,
Open csharp in the same directory.
Give the command in csharp:
csharp> using System.IO;
Then paste the lines above.
Outside of csharp you can look at UpperText.txt.
This example of line by line processing was intended to be simple. In fact this processing is so simple, we could consider the whole file as one big string. We could get the same result if the entire while loop were replaced by:
string contents = reader.ReadToEnd();
writer.Write(contents.ToUpper());
ReadToEnd does not strip off a newline, like ReadLine does, so we do not want to add an extra newline when writing. We use Write instead of WriteLine.