finish lecture 12, add invert to special slide snippets
parent
9646c62fe8
commit
7a2601d0c6
File diff suppressed because one or more lines are too long
@ -1,295 +1,233 @@
|
|||||||
# Files and Streams
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
marp: true
|
||||||
# Overview
|
paginate: true
|
||||||
|
math: mathjax
|
||||||
Files and Streams
|
theme: buutti
|
||||||
|
title: 12. Files and Streams
|
||||||
Reading from a File
|
---
|
||||||
|
|
||||||
Writing to a File
|
|
||||||
|
|
||||||
JSON Serialization
|
|
||||||
|
|
||||||
JSON Deserialization
|
|
||||||
|
|
||||||
# Files and Streams
|
# Files and Streams
|
||||||
|
|
||||||
The .NET library contains classes for manipulating files and directories
|
<!-- headingDivider: 5 -->
|
||||||
|
<!-- class: invert -->
|
||||||
The FileStream class contains methods for read and write operations for files
|
|
||||||
|
|
||||||
The goal is usually to turn the data in your code into an outside resource, such as a .txt file, and vice versa
|
|
||||||
|
|
||||||
Application Code
|
|
||||||
|
|
||||||
Stream writer / reader
|
## Overview
|
||||||
|
|
||||||
String, int, ...
|
* Files and Streams
|
||||||
|
* Reading from a File
|
||||||
|
* Writing to a File
|
||||||
|
* JSON Serialization
|
||||||
|
* JSON Deserialization
|
||||||
|
|
||||||
FileStream object
|
## Files and streams
|
||||||
|
|
||||||
.txt, .csv, .png, ...
|
* The .NET library [contains classes](https://learn.microsoft.com/en-us/dotnet/api/system.io?view=net-7.0
|
||||||
|
) for manipulating files and directories
|
||||||
|
* The `FileStream` class contains methods for read and write operations for files
|
||||||
|
* The goal is usually to turn the data in your code into an outside resource, such as a .txt file, and vice versa
|
||||||
|
|
||||||
---
|

|
||||||
|
|
||||||
https://learn.microsoft.com/en-us/dotnet/api/system.io?view=net-7.0
|
|
||||||
|
|
||||||
# Using the File Class
|
|
||||||
|
|
||||||
To get started, add the following namespace to your project:
|
## Using the `File` Class
|
||||||
|
|
||||||
|
* To get started, add the following namespace to your project:
|
||||||
|
```csharp
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
```
|
||||||
System.IO provides basic directory and folder support, and allows reading and writing to files and data streams
|
* `System.IO` provides basic directory and folder support, and allows reading and writing to files and data streams
|
||||||
|
* Check if a file exists with the `.Exists()` method:
|
||||||
Check if a file exists with the .Exists() method:
|
```csharp
|
||||||
|
|
||||||
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
|
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
|
||||||
|
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Console.WriteLine($"The file {path} does not exist.");
|
Console.WriteLine($"The file {path} does not exist.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
## Reading from a file
|
||||||
|
|
||||||
https://learn.microsoft.com/en-us/dotnet/api/system.io?view=net-7.0
|
|
||||||
|
|
||||||
# Reading from a File
|
|
||||||
|
|
||||||
Get the entire document as a string with File.ReadAllText
|
|
||||||
|
|
||||||
Get all lines of a document as a string array with File.ReadAllLines
|
|
||||||
|
|
||||||
|
* Get the entire document as a string with `File.ReadAllText`
|
||||||
|
* Get all lines of a document as a string array with `File.ReadAllLines`
|
||||||
|
```csharp
|
||||||
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
|
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
|
||||||
|
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Console.WriteLine($"The file {path} does not exist.");
|
Console.WriteLine($"The file {path} does not exist.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
var allLines = File.ReadAllLines(path);
|
var allLines = File.ReadAllLines(path);
|
||||||
|
|
||||||
foreach (string line in allLines)
|
foreach (string line in allLines)
|
||||||
|
|
||||||
Console.WriteLine(line);
|
Console.WriteLine(line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# Writing to a File
|
## Writing to a file
|
||||||
|
|
||||||
Writing to a file is done with File.WriteAllText and File.WriteAllLines methods:
|
* Writing to a file is done with `File.WriteAllText` and `File.WriteAllLines` methods:
|
||||||
|
|
||||||
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
|
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
string path = @"C:\Users\Public\TestFolder\TestFile.txt";
|
||||||
string[] lyrics = new string[]
|
string[] lyrics = new string[]
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
"Hello",
|
"Hello",
|
||||||
|
|
||||||
"Is it me you're looking for",
|
"Is it me you're looking for",
|
||||||
|
|
||||||
"I can see it in your eyes",
|
"I can see it in your eyes",
|
||||||
|
|
||||||
"I can see it in your smile"
|
"I can see it in your smile"
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
File.Delete(path); // If file exists, deletes the old file
|
File.Delete(path); // If file exists, deletes the old file
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
File.WriteAllLines(path, lyrics); // Creates a new file with lyrics
|
File.WriteAllLines(path, lyrics); // Creates a new file with lyrics
|
||||||
|
```
|
||||||
|
|
||||||
# Exercise 1: A Simple Parser
|
|
||||||
|
|
||||||
Create a console application which keeps asking the user for a string. Each string is added into a list of strings.
|
|
||||||
|
|
||||||
If the user returns an empty string, the program asks for a path to a .txt file.
|
## Exercise 1: A simple parser
|
||||||
|
<!--_class: exercise -->
|
||||||
|
|
||||||
If the file exists, its contents are replaced with each string written to a separate line. If not, a new file with the contents is created.
|
1. Create a console application which keeps asking the user for a string. Each string is added into a list of strings.
|
||||||
|
2. If the user returns an empty string, the program asks for a path to a .txt file.
|
||||||
|
3. If the file exists, its contents are replaced with each string written to a separate line. If not, a new file with the contents is created.
|
||||||
|
|
||||||
# JSON Serialization
|
## JSON
|
||||||
|
|
||||||
* JSON (JavaScript Object Notation) is a way to represent code objects in text form, a "data-interchange format"
|
* [JSON](https://www.json.org/json-en.html) (JavaScript Object Notation) is a way to represent code objects in text form, a "data-interchange format"
|
||||||
* Enables reading and writing series of objects into a text file
|
* Enables reading and writing series of objects into a text file
|
||||||
* Consists of two types of structures
|
* Consists of two types of structures
|
||||||
* Objects, or unordered name-value pairs
|
* Objects, or unordered name-value pairs
|
||||||
* Ordered lists of values
|
* Ordered lists of values
|
||||||
* Language-independent, although the JSON notation resembles the C-family of languages (C#, Java, JavaScript etc.)
|
* Language-independent, although the JSON notation resembles the C-family of languages (C#, Java, JavaScript etc.)
|
||||||
---
|
|
||||||
|
|
||||||
https://www.json.org/json-en.html
|
|
||||||
|
|
||||||
# JSON Serialization (continued)
|
|
||||||
|
### JSON Serialization: set-up
|
||||||
|
|
||||||
* .NET projects do not directly support JSON serialization
|
* .NET projects do not directly support JSON serialization
|
||||||
* A __NuGet package__ for that exists, called __Newtonsoft.Json __
|
* A *__NuGet package__* for that exists, called `Newtonsoft.Json`
|
||||||
* Install the package from _Tools _ -> _NuGet Package Manager_ -> M _anage NuGet Packages for Solution…_
|
* Install the package from _Tools > NuGet Package Manager > Manage NuGet Packages for Solution…_
|
||||||
* Select _Browse_
|
* Select _Browse_
|
||||||
* The _Newtonsoft.Json_ should be the topmost package. If not, search for it from the search bar
|
* The _Newtonsoft.Json_ should be the topmost package. If not, search for it from the search bar
|
||||||
* Select the package, check the checkbox next to _Project_ and click _Install_
|
* Select the package, check the checkbox next to _Project_ and click _Install_
|
||||||
|
|
||||||
You can __serialize __ an object (e.g. a list) into a JSON string with the JsonConvert.SerializeObject() method:
|
### JSON Serialization: an example
|
||||||
|
|
||||||
class Product
|
You can *__serialize__* an object (e.g. a list) into a JSON string with the `JsonConvert.SerializeObject()` method:
|
||||||
|
|
||||||
{
|
<div class='columns21' markdown='1'>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Product
|
||||||
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
List<Product> products = new List<Product>
|
List<Product> products = new List<Product>
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
new Product{Id=1, Name="Awesome Product"},
|
new Product{Id=1, Name="Awesome Product"},
|
||||||
|
|
||||||
new Product{Id=2, Name="Terrible Product"}
|
new Product{Id=2, Name="Terrible Product"}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
string jsonString = JsonConvert.SerializeObject(products);
|
string jsonString = JsonConvert.SerializeObject(products);
|
||||||
|
File.WriteAllText(@"C:\Users\OMISTAJA\source\repos\Example\Products.json", jsonString);
|
||||||
File.WriteAllText(@"C:\\Users\\OMISTAJA\\source\\repos\\Example\\Products.json", jsonString);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||
The contents of the output file Products.json are as follows:
|
The contents of the output file Products.json are as follows:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
# JSON Deserialization
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
__Deserializing __ the contents of a JSON file into an object in your program can be done with the JsonConvert.DeserializeObject() method:
|
## JSON Deserialization
|
||||||
|
|
||||||
string json = File.ReadAllText(
|
*__Deserializing__* the contents of a JSON file into an object in your program can be done with the `JsonConvert.DeserializeObject()` method:
|
||||||
|
|
||||||
@"C:\\Users\\Johannes\\source\\repos\\Luentoesimerkit\\Luentoesimerkit\\db.json");
|
```csharp
|
||||||
|
string json = File.ReadAllText(
|
||||||
|
@"C:\Users\OMISTAJA\source\repos\Luentoesimerkit\Luentoesimerkit\db.json");
|
||||||
|
|
||||||
List<Product> deserializedProducts = new List<Product>();
|
List<Product> deserializedProducts = new List<Product>();
|
||||||
|
|
||||||
deserializedProducts = JsonConvert.DeserializeObject<List<Product>>(json);
|
deserializedProducts = JsonConvert.DeserializeObject<List<Product>>(json);
|
||||||
|
|
||||||
foreach(Product product in deserializedProducts)
|
foreach(Product product in deserializedProducts)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Console.WriteLine(product.Name);
|
Console.WriteLine(product.Name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# Exercise 2: Serializing Your Classes
|
## Exercise 2: Serializing Your Classes
|
||||||
|
<!--_class: exercise -->
|
||||||
Create a class Note with the properties int Id, DateTime TimeStamp and string Text.
|
|
||||||
|
|
||||||
Create a main loop that keeps asking the user for a new note.
|
|
||||||
|
|
||||||
After the user has entered each note, a new Note object is created with a running Id (1, 2, 3…), TimeStamp set to current time and Text is the inputted note. Each new note is added to a list of notes, allNotes.
|
|
||||||
|
|
||||||
Every time a new note is submitted, the allNotes list is serialized into a json file, "notes.json". Set the path to the current project path (you can get the path by right-clicking the project in solution explorer and selecting "Copy Full Path". Remember to change the file name!)
|
1. Create a class `Note` with the properties `int Id`, `DateTime TimeStamp` and `string Text`.
|
||||||
|
2. Create a main loop that keeps asking the user for a new note.
|
||||||
|
3. After the user has entered each note, a new `Note` object is created with a running `Id` (1, 2, 3…), `TimeStamp` set to current time and `Text` as the inputted note. Each new note is added to a list of notes `allNotes`.
|
||||||
|
4. Every time a new note is submitted, the `allNotes` list is serialized into a json file `notes.json`. Set the path to the current project path (you can get the path by right-clicking the project in solution explorer and selecting _Copy Full Path_. Remember to change the file name!)
|
||||||
|
|
||||||
# FileStream
|
## Extra: FileStream
|
||||||
|
<!-- _class: extra -->
|
||||||
The files have to be opened before read/write and closed after
|
|
||||||
|
|
||||||
Behind the scenes, the ReadAll... and WriteAll… methods automatically do the opening and closing, as described in the Microsoft documentation:
|
|
||||||
|
|
||||||
|
* The files have to be opened before reading or writing and closed after
|
||||||
|
* Behind the scenes, the `ReadAll...` and `WriteAll...` methods automatically do the opening and closing, as described in the Microsoft documentation:
|
||||||

|

|
||||||
|
* Writing to or reading only a part of the file requires opening and closing the file manually
|
||||||
|
* This creates a *__FileStream__* object that can be used for accessing parts of the file
|
||||||
|
|
||||||
Writing to or reading only a part of the file requires opening and closing the file manually
|
## FileStream (continued)
|
||||||
|
<!-- _class: "extra invert" -->
|
||||||
This creates a __FileStream __ object that can be used for accessing parts of the file
|
|
||||||
|
|
||||||
# FileStream (continued)
|
* When inserting string data into a file, it needs to be converted into bytes
|
||||||
|
|
||||||
When inserting string data into a file, it needs to be converted into bytes
|
|
||||||
|
|
||||||
string path = @"C:\\Users\\Public\\TestFolder\\TestWriteFile.txt";
|
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
string path = @"C:\Users\Public\TestFolder\TestWriteFile.txt";
|
||||||
int nOfLines = 4;
|
int nOfLines = 4;
|
||||||
|
|
||||||
FileStream fs = null;
|
FileStream fs = null;
|
||||||
|
|
||||||
if (!File.Exists(path)) // If file does not exist
|
if (!File.Exists(path)) // If file does not exist
|
||||||
|
|
||||||
fs = File.Create(path); // create a new file and open it
|
fs = File.Create(path); // create a new file and open it
|
||||||
|
|
||||||
else // If file exists
|
else // If file exists
|
||||||
|
|
||||||
fs = File.OpenWrite(path); // open an existing file for writing
|
fs = File.OpenWrite(path); // open an existing file for writing
|
||||||
|
|
||||||
for (int i = 0; i < nOfLines; ++i)
|
for (int i = 0; i < nOfLines; ++i)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
string input = Console.ReadLine() + "\\n"; // Read user input, add newline
|
string input = Console.ReadLine() + "\\n"; // Read user input, add newline
|
||||||
|
|
||||||
byte[] byteInput = new UTF8Encoding(true).GetBytes(input); // Get the string as a sequence of bytes
|
byte[] byteInput = new UTF8Encoding(true).GetBytes(input); // Get the string as a sequence of bytes
|
||||||
|
|
||||||
fs.Write(byteInput, 0, byteInput.Length); // Write the bytes at the end of the file
|
fs.Write(byteInput, 0, byteInput.Length); // Write the bytes at the end of the file
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.Close(); // Close the file
|
fs.Close(); // Close the file
|
||||||
|
```
|
||||||
|
|
||||||
# The Using Statement
|
## Extra: The `using` statement
|
||||||
|
<!-- _class: "extra invert" -->
|
||||||
From the Microsoft Documentation about the FileStream class:
|
|
||||||
|
|
||||||
|
* From the Microsoft Documentation about the FileStream class:
|
||||||

|

|
||||||
|
* This means that wrapping the file handling in an `using` block handles the opening and closing of the stream for you
|
||||||
|
|
||||||
This means that wrapping the file handling in an __using __ block handles the opening and closing of the stream for you
|
---
|
||||||
|
<!-- _class: "extra invert" -->
|
||||||
|
|
||||||
The following reads the first 20 characters of a file and prints them to the console
|
The following reads the first 20 characters of a file and prints them to the console
|
||||||
|
|
||||||
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
|
```csharp
|
||||||
|
string path = @"C:\Users\Public\TestFolder\TestFile.txt";
|
||||||
int nOfBytesToPrint = 20;
|
int nOfBytesToPrint = 20;
|
||||||
|
|
||||||
byte[] byteArray = new byte[nOfBytesToPrint];
|
byte[] byteArray = new byte[nOfBytesToPrint];
|
||||||
|
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
|
|
||||||
Console.WriteLine($"The file {path} does not exist.");
|
Console.WriteLine($"The file {path} does not exist.");
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
using (FileStream fs = File.OpenRead(path))
|
using (FileStream fs = File.OpenRead(path))
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
fs.Read(byteArray, 0, nOfBytesToPrint);
|
fs.Read(byteArray, 0, nOfBytesToPrint);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// No need to close the file since it was handled inside of a using block
|
// No need to close the file since it was handled inside of a using block
|
||||||
|
|
||||||
Console.WriteLine(Encoding.UTF8.GetString(byteArray, 0, byteArray.Length));
|
Console.WriteLine(Encoding.UTF8.GetString(byteArray, 0, byteArray.Length));
|
||||||
|
```
|
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
Loading…
Reference in New Issue