We have already discussed and used the UI
class to aid keyboard input.
Now we are going to develop an FIO
class for our libraries. The FIO
class aids
file input and output with Xamarin Studio, and illustrates a number of
more generally useful ideas.
You saw in the last section how we might refer to numbers.txt
in different
ways depending on the execution environment. Our situation
is based on the particular choices made by the creators of Xamarin Studio.
More generally, there are many times when a program may need a file
that may be stored in one of several directories.
Our FIO
class will address this issue, and we will set up the
parameters to work specifically with both Xamarin Studio and command line
development.
We use one idea that is discussed more in the next chapter: We need a sequence
of directory strings to look through. At this point we have only discussed
sequences of individual characters. The variable paths
contains a sequence of directory paths to check. In our case we make the
sequence contain
"."
, the current directory, ".."
, the parent directory, and
Path.Combine("..", "..")
, the parent’s parent.
We make paths
a static variable, so
it is visible in all the functions in the class.
Then the sequence paths
can be used in the foreach
loop:
/// Find a directory containing the filename
/// and return the full file path, if it exists.
/// Otherwise return null.
public static string GetPath(string filename)
{
foreach (string dir in paths) {
string filePath = Path.Combine(dir, filename);
if (File.Exists(filePath))
return filePath;
}
return null;
}
For each directory path in paths
, we create a filePath
as if the
file were in that directory. We return the first path that actually exists.
We allow for the file to not be in any of the directories in paths
. If
we do not find it, we return null
(no object).
For convenience, we have an elaboration, using GetPath
,
that directly opens the file to read:
/// Find a directory containing filename;
/// return a new StreamReader to the file
/// or null if the file does not exist.
public static StreamReader OpenReader(string filename)
{
string filePath = GetPath(filename);
if (filePath == null)
return null;
else
return new StreamReader( filePath);
}
We have a variation on GetPath
that just return the path to the
directory containing the file. Here is the heading:
/// Return a directory conaining the filename, if it exists.
/// Otherwise return null.
public static string GetLocation(string filename)
This is useful in case you want to later write into the same directory
that you read from. You can get a location from GetLocation
and then
write to the same directory, creating a StreamWriter
. Use the convenience
function:
/// Join the location directory and filename;
/// open and return a StreamWriter to the file.
public static StreamWriter OpenWriter(string location, string filename)
{
string filePath = Path.Combine(location, filename);
return new StreamWriter(filePath);
}
The entire FIO
class is in
fio/fio.cs
We illustrate the use of FIO
functions in example file
fio_usage/fio_usage.cs:
using System;
using System.IO;
namespace IntroCS
{
class FIOTest
{
public static void Main(string[] args)
{
string sample = "sample.txt";
string output = "output.txt";
Console.WriteLine("Directory of {0}: {1}",
sample, FIO.GetLocation(sample));
Console.WriteLine("Path to {0}: {1}",
sample, FIO.GetPath(sample));
StreamReader reader1 = FIO.OpenReader(sample);
if (reader1 != null) {
Console.Write(reader1.ReadToEnd());
Console.WriteLine("First reader test passed.");
reader1.Close();
}
StreamReader reader2 = FIO.OpenReader(FIO.GetLocation(sample),
sample);
if (reader2 != null) {
Console.WriteLine("Second reader test passed.");
reader2.Close();
}
StreamWriter writer1 = FIO.OpenWriter(FIO.GetLocation(sample),
output);
writer1.WriteLine("File in the same directory as {0}.", sample);
writer1.Close();
Console.WriteLine("Writer test passed; file written at \n {0}",
FIO.GetPath(output));
}
}
}
IF you look at the fio_usage project in our examples solution, you see that
sample.txt
is a file in the project folder. The program
ends up writing to a new file in the same (project) directory. Remember that even
though the new file output.txt
appears in the project directory, it does not appear in the
Solution pad unless you add it to the project. You can see it in the file system,
and open it if you like.
If you want to open a terminal/console and go to the project directory, you can compile and run this program, and it will still work, even though the current directory has changed.
You are encouraged to make a library project fio in your work solution, copying
the fio.cs file. (Follow instruction like for ui in
Library Projects in Xamarin Studio (Optional).) You can test your new library by also
copying the fio_test project to your solution.
If you do this now and stick to one work solution, then you will be ready for
several later uses of FIO
.
Complete the function described below, and make a Main program and sample file to test it:
/// Take all lines from reader that do not start with startToRemove
/// and copy them to writer.
static void FileLineRemoval(StreamReader reader, StreamWriter writer
char startToRemove)
For example, in Unix/Mac scripts lines starting with '#'
are
comment lines. Making startToRemove
be '#'
would write only non-comment lines
to the writer.