Since I expect you will have extensive experience working with standard input/output in your previous computer
programming courses, it would be useful to highlight the subtle differences C# handles console I/O. For example,
in C++, you might have done something like this:
cin >> myChar; // to read a single character from standard input
getline(cin, myString); // to store all characters up until the carriage return, into a string
In Java, you would have had to do a little more legwork...
Scanner sc = new Scanner(System.in);
String myString = sc.next(); // to read a single "token"
String wholeLine = sc.readline(); // to read a whole line
(Declaring a
Scanner object before using it?! Java can be exhausting sometimes...)
C# will handle standard input more like how Java does.
ConsoleKeyInfo ReadKey() // reads a single character
ConsoleKeyInfo ReadKey(bool Show) // same thing but if Show is true, the key is not displayed
string ReadLine() // functionally identical to "getline" or "readline" from C++/Java, respectively
The
ConsoleKeyInfo return types above are structures, which describe each key press,
including the combination of keys and locks. If you just want the character, you would do
Console.ReadKey().KeyChar.
Output will, again, look more familiar to Java (or C programmers) than it does to C++. There's a
Write version that sends the argument to standard output
without a newline character at
end, and
WriteLine that will include a newline character at the end. You can format
output in two different ways (the first will look familiar to Java programmers, the second will look familiar to
C programmers):
System.Console.WriteLine("My name is " + myName + " and I am pretty great!");
System.Console.WriteLine("Your name is {0} and you are pretty great, too!", yourName);
Where you would increment the value inside the curly braces to refer to any number of variables you can list
after the "string format" has been defined.
One thing that C# fumbles with is reading non-string types from input streams. While the >> operator in
C++ will implicitly typecast the input based on the data type of the right operand (i.e.
cin >> myInt; will attempt to read an integer, if
myInt is defined as an
integer... which we would all well and hope it is, with a name like that!) or how there's many versions of
the
next method of
Scanner in the Java language, C# has
to use an intermediate
Convert static class of methods in order to typecast the
string-based input as something else. For example, to read a number, you would do:
int myInt = Convert.ToInt32(Console.ReadLine());
But could also do:
int myOtherInt = Int32.Parse(Console.ReadLine());
to achieve the same objective of reading a single number from standard input.
The observant reader may have noticed how we're using
ReadLine above, which can be
problematic if I, say, write out two numbers separated by a space before hitting the enter key. To compensate
for this (again, where I feel like C# fumbled), you could do something like this:
string[] tokens = Console.ReadLine().Split();
for (int i = 0; i < tokens.Length; i++)
myArray[i] = Convert.ToInt32(tokens[i]);
Compensating for non-integer input here is just as problematic as compensating for non-integer input from
other languages, though. Generally speaking, if you can't assume something regular about the type of input
you're receiving or the order those data types will appear, you're going to have a bad time.
Something neat you can do with standard output in C# is modify the color/style of the output generated. For
example, you can change the background/text color produced by doing something like:
System.Console.BackgroundColor = ConsoleColor.White;
System.Console.ForegroundColor = ConsoleColor.Red;
System.Console.WriteLine("This text will be in red, on a white background.");
You can then restore the default color scheme by using
System.Console.ResetColor().
File I/O
File input/output will function similar as with C++ and Java, although the syntax used will be slightly
different. Because everyone needs their own shtick. Let's consider one example where I'd like to read the
contents of an input file, and simply write them out to standard output.
namespace Testing
{
public class TestClass
{
public static void Main()
{
string slacker;
using (StreamReader inFile = new StreamReader("input.txt"))
{
slacker = inFile.ReadLine(); // remember to "prime the read"
while (slacker != null)
{
System.Console.WriteLine(slacker);
slacker = inFile.ReadLine();
}
}
}
}
}
The
using statement above acts as a sort of open/close function we might otherwise
have had to call before/after the loop. Once we've sequentially reached inside of the bold curly braces
highlighted above,
inFile will be "open". Once we've gone past the closing curly
brace of that pair,
inFile will be "closed". Which I think is pretty convenient!
On the flip side, let's look at how I might write everything I type at the keyboard, into an output file.
namespace Testing // Yes, I did cut 'n paste this
{
public class TestClass
{
public static void Main()
{
string slacker = "slacker";
using (StreamWriter outFile = new StreamWriter("output.txt"))
{
while (slacker.CompareTo("q") != 0) // slacker != "q"
{
System.Console.Write("Type in 'q' in order to exit. ");
slacker = System.Console.ReadLine();
outFile.WriteLine(slacker);
}
}
}
}
}
The two above examples don't address the possibility of something going wrong with opening/using/closing
these file streams, though, which would certainly be something you'd want to have included in your functional
programs. Things like:
if (File.Exists("input.txt")) // "Does this file even exist before I try to use it?"
// File is a static class, so there's no need to declare it anywhere
FileAttributes stats = File.GetAttributes("output.txt");
if ( (stats & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
System.Console.WriteLine("I can't write to a readonly file!");
else
System.Console.WriteLine("All ready to begin writing!");