7.5. Lab: Files

7.5.1. Example: Sum Numbers in File

  • StreamReader

  • .EndOfStream

  • .Close()

  • negation

  • ReadLine

  • .Trim()

  • int.Parse()

You have summed the numbers from 1 to n. In that case you generated the next number i automatically using i++. We could also write a method to 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();     // Trim(()
      sum += int.Parse(sVal);
   }
   reader.Close();
   return sum;
}

Below is a more elaborate, complete example with some data quality control, that also exits gracefully if you give a bad file name. If you give a good file name, it skips lines that contain only whitespace.

Note

Note that this example uses the UI class. You can simply copy the file ui.cs to the project folder like before.

using System;
using System.IO;

namespace IntroCSCS
{
   class SumFile  // sum a file integers, one per line
   {
      static void Main()
      {
         string filename = UI.PromptLine(
                              "Enter the name of a file of integers: ");
         if (File.Exists(filename)) {
            Console.WriteLine("The sum is {0}", CalcSum(filename));
         }
         else {
            Console.WriteLine("Bad file name {0}", filename);
         }
      }

      /// Open, read and close the named file and
      /// return 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 method used in Main for avoiding filename typo errors is File.Exists in the System.IO namespace

bool File.Exists(string filenamePath)

It is true if the named files exists in the operating system’s file structure. For files in the current folder, you can just use the plain file name.

7.5.2. Safe Sum File

  1. From sum_file/sum_file.cs, copy the method CalcSum and the logic in the Main to your project Program.cs of the chapter to make sure it works. Afterwards, write a new method with the header below. Use it in Main, in place of the if statement that checks (only once) for a legal file:

    // Prompt the user to enter a file name to open for reading.
    // Repeat until the name of an existing file is given.
    // Open and return the file.
    public static StreamReader PromptFile(string prompt)
    
  2. A user who completely forgot the file name could be stuck in an infinite loop! Elaborate the method and program, so that an empty line entered means “give up”, and null (no object) should be returned. The main program needs to test for this and quit gracefully in that case.

7.5.3. Copy to Upper Case

Here is a simple fragment from example file copy_upper/copy_upper.cs. It copies a file line by line to a new file in upper case:

var reader = new StreamReader("text.txt");
var writer = new StreamWriter("upper_text.txt");
while (!reader.EndOfStream) {
   string line = reader.ReadLine();
   writer.WriteLine(line.ToUpper());
}
reader.Close();
writer.Close();

This is another case where the ReadToEnd method could have eliminated the loop:

string contents = reader.ReadToEnd();
writer.Write(contents.ToUpper());