{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cfbe1ca5",
   "metadata": {},
   "source": [
    "# Lab: Files\n",
    "\n",
    "```{index} example; sum_files.cs\n",
    "```\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79c6c329",
   "metadata": {},
   "source": [
    "## Example: Sum Numbers in File\n",
    "\n",
    "- StreamReader\n",
    "- .EndOfStream\n",
    "- .Close()\n",
    "- negation\n",
    "- ReadLine\n",
    "- .Trim()\n",
    "- int.Parse()\n",
    "\n",
    "You have summed the numbers from 1 to `n`. In that case you generated\n",
    "the next number `i` automatically using `i++`. We could also write a\n",
    "method to read numbers from a file containing one number per line\n",
    "(plus possible white space):\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1fcad285",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "static int CalcSum(string filename)\n",
    "{\n",
    "   int sum = 0;\n",
    "   var reader = new StreamReader(filename);\n",
    "   while (!reader.EndOfStream) {\n",
    "      string sVal = reader.ReadLine().Trim();     // Trim(()\n",
    "      sum += int.Parse(sVal);\n",
    "   }\n",
    "   reader.Close();\n",
    "   return sum;\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96256d84",
   "metadata": {},
   "source": [
    "\n",
    "```{index} File class; Exists\n",
    "```\n",
    "\n",
    "Below is a more elaborate, complete example with some data quality control,\n",
    "that also exits gracefully if you give a bad file name.\n",
    "If you give a good file name, it skips lines that contain only whitespace.\n",
    "\n",
    "> :::{note}\n",
    "> Note that this example uses the `UI` class. You can simply copy the file\n",
    "> `ui.cs` to the project folder like before.\n",
    "> :::\n",
    "\n",
    "```{literalinclude} ../../examples/sum_file/sum_file.cs\n",
    "```\n",
    "\n",
    "A useful method used in `Main` for avoiding filename typo errors\n",
    "is `File.Exists` in the `System.IO` namespace\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "960b5eeb",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "bool File.Exists(string filenamePath)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fd3210b",
   "metadata": {},
   "source": [
    "It is true if the named files exists in the operating system's file structure.\n",
    "For files in the current folder, you can just use the plain file name.\n",
    "\n",
    "% bin/debug\n",
    "% It is in the right form for the program.  If you run the program and enter the\n",
    "% response:\n",
    "%\n",
    "% .. code-block:: none\n",
    "%\n",
    "%    numbers.txt\n",
    "%\n",
    "% you should be told that the file does not exist.  Recall that the executable\n",
    "% created by Xamarin Studio is two directories down through :file:`bin`\n",
    "% to :file:`Debug`.  This is the default\n",
    "% *current directory* when Xamarin Studio runs the program.\n",
    "% You can refer to\n",
    "% a file that is not in the current directory.\n",
    "% A full description is in the next section, but briefly, what we need now:\n",
    "% The symbol for the parent directory is ``..``.\n",
    "% The hierarchy of folders and files are separated by\n",
    "% ``\\`` in Windows and ``/`` on a Mac,  so you can test the program successfully\n",
    "% if you use the file name:\n",
    "% ``..\\..\\numbers.txt`` in Windows and ``../../numbers.txt`` on a Mac.  On a Mac, running\n",
    "% the program looks like:\n",
    "%\n",
    "% .. code-block:: none\n",
    "%\n",
    "%    Enter the name of a file of integers: ../../numbers.txt\n",
    "%    The sum is 16\n",
    "\n",
    "% bin/Debug\n",
    "% In :ref:`fio` we will discuss a more flexible way of finding files to open,\n",
    "% that works well in Xamarin Studio and many other situations."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96dcb4e0",
   "metadata": {},
   "source": [
    "```{index} exercise; safe sum\n",
    "```\n",
    "\n",
    "(safe-sum-file-ex)=\n",
    "\n",
    "## Safe Sum File\n",
    "\n",
    "1. From [sum_file/sum_file.cs](https://github.com/mstbit/introcs-csharp-examples/blob/master/sum_file/sum_file.cs), copy the method CalcSum\n",
    "   and the logic in the Main to your project Program.cs of the chapter to make sure it works.\n",
    "   Afterwards, write a new method with the header below. Use it in `Main`, in place of the `if`\n",
    "   statement that checks (only once) for a legal file:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "770d21c4",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "   // Prompt the user to enter a file name to open for reading.\n",
    "   // Repeat until the name of an existing file is given.\n",
    "   // Open and return the file.\n",
    "   public static StreamReader PromptFile(string prompt)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4ac1063",
   "metadata": {},
   "source": [
    "\n",
    "2. A user who completely forgot the file name could be stuck in an infinite loop!\n",
    "   Elaborate the method and program, so that an empty line entered means\n",
    "   \"give up\", and `null` (no object) should be returned. The main program needs to\n",
    "   test for this and quit gracefully in that case.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b18cf41",
   "metadata": {},
   "source": [
    "## Copy to Upper Case\n",
    "\n",
    "Here is a simple fragment from example file [copy_upper/copy_upper.cs](https://github.com/mstbit/introcs-csharp-examples/blob/master/copy_upper/copy_upper.cs).\n",
    "It copies a file line by line to a new file in upper case:\n",
    "\n",
    "```{literalinclude} ../../examples/copy_upper/copy_upper.cs\n",
    ":dedent: 9\n",
    ":end-before: chunk\n",
    ":start-after: chunk\n",
    "```\n",
    "\n",
    "This is another case where the `ReadToEnd` method could have eliminated the loop:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a3a4a0af",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "string contents = reader.ReadToEnd();\n",
    "writer.Write(contents.ToUpper());\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3f082703",
   "metadata": {},
   "source": [
    "# Lab: Text Processing"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9eac738c",
   "metadata": {},
   "source": [
    "## Goal\n",
    "\n",
    "Build a program that reads a text file of student records and writes a clean summary report."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "256d6541",
   "metadata": {},
   "source": [
    "## Input format\n",
    "\n",
    "Each line should look like:\n",
    "\n",
    "```text\n",
    "Name,Score,Major\n",
    "```\n",
    "\n",
    "Example:\n",
    "\n",
    "```text\n",
    "Ada,98,CS\n",
    "Bob,87,Math\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35d00b17",
   "metadata": {},
   "source": [
    "## Requirements\n",
    "\n",
    "1. Read all lines from an input file.\n",
    "2. For each line:\n",
    "   - trim fields\n",
    "   - validate field count\n",
    "   - parse score with `TryParse`\n",
    "3. For valid records:\n",
    "   - print normalized output\n",
    "   - track count and average score\n",
    "4. For invalid records:\n",
    "   - print a warning with line content\n",
    "5. Write final summary to an output file."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6df66ac3",
   "metadata": {},
   "source": [
    "## Suggested extensions\n",
    "\n",
    "- highest and lowest score\n",
    "- count by major\n",
    "- reject duplicate names"
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "csharp"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
