3. Objectives
• To learn how to approach common I/O tasks in
.NET
• To understand the best practices of file and stream
I/O in general
• To get an overview of the data display controls of
WPF
3 / 58
4. Streams
• Sequence of bytes read from or written to a backing
store (e.g. disk, memory)
• Provide three fundamental operations:
• Reading
• Writing
• Seeking
• Abstraction from the specific details of the operation
system and underlying devices
• FileStream
• NetworkStream
• MemoryStream
• CryptoStream
4 / 58
5. Files
• Ordered and names collection of bytes that have
persistent storage
• Disks contain directories, directories contain files
• Can be created, copied, deleted, moved, read from
and written to
5 / 58
6. File I/O in .NET
• System.IO namespace features classes for…
• Reading from files and streams
• Writing to files and streams
• Accessing file and directory information
• Readers and Writers wrap streams to handle
conversion of encoded characters to and from
bytes
• BinaryReader, BinaryWriter
• TextReader, TextWriter
6 / 58
7. FileInfo Class
• Provides typical operations such as copying,
moving, renaming, creating, opening, deleting, and
appending to files
• Can be faster for performing multiple operations on
the same file, because a security check will not
always be necessary
• Grants full read/write access to new files by default
7 / 58
8. Creating New Files
C#
8 / 58
// Collect information on the file to create.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Create new file.
FileStream fileStream = fileInfo.Create();
// ...
// Close file stream and release all resources.
fileStream.Close();
9. Gotcha!
You should always release any files
after you’re finished!
The user will thank you for that.
9 / 58
11. Writing Text To Files
C#
11 / 58
// Collect information on the file to create.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Create new file.
FileStream fileStream = fileInfo.Create();
// Create new text writer.
TextWriter textWriter = new StreamWriter(fileStream);
// Write text.
textWriter.WriteLine("Hello World!");
// Close file stream and release all resources.
textWriter.Close();
12. Writing Encoded Text To Files
C#
12 / 58
// Collect information on the file to create.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Create new file.
FileStream fileStream = fileInfo.Create();
// Create new text writer.
TextWriter textWriter = new StreamWriter(fileStream, Encoding.UTF8);
// Write text.
textWriter.WriteLine("Hello World!");
// Close file stream and release all resources.
textWriter.Close();
13. Reading Text From Files
C#
13 / 58
// Collect information on the file to read from.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Open file for reading.
FileStream fileStream = fileInfo.OpenRead();
// Create new text reader.
TextReader textReader = new StreamReader(fileStream);
// Read text.
string s;
while ((s = textReader.ReadLine()) != null)
{
Console.WriteLine(s);
}
// Close file stream and release all resources.
textReader.Close();
14. Appending Text To Files
C#
14 / 58
// Collect information on the file to append text to.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Open file for writing.
TextWriter textWriter = fileInfo.AppendText();
// Append text.
textWriter.WriteLine("new line");
// Close file stream and release all resources.
textWriter.Close();
15. Renaming and Moving Files
C#
15 / 58
// Collect information on the file to rename.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Rename file.
fileInfo.MoveTo("movedFile.txt");
16. Deleting Files
C#
16 / 58
// Collect information on the file to delete.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Delete file.
fileInfo.Delete();
17. Checking Whether Files Exist
C#
17 / 58
// Collect information on the file to delete.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Check if file exists.
if (fileInfo.Exists)
{
// Delete file.
fileInfo.Delete();
}
18. Accessing File Info
C#
18 / 58
// Collect information on the file.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Show information on console.
Console.WriteLine("File name: {0}", fileInfo.Name);
Console.WriteLine("File size (in bytes): {0}", fileInfo.Length);
Console.WriteLine("Read-only: {0}", fileInfo.IsReadOnly);
Console.WriteLine("Modified: {0}", fileInfo.LastWriteTime);
19. Accessing File Info
C#
19 / 58
// Collect information on the file.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Show information on console.
Console.WriteLine("File name: {0}", fileInfo.Name);
Console.WriteLine("File size (in bytes): {0}", fileInfo.Length);
Console.WriteLine("Read-only: {0}", fileInfo.IsReadOnly);
Console.WriteLine("Modified: {0}", fileInfo.LastWriteTime);
Console Output
File name: newFile.txt
File size (in bytes): 10
Read-only: False
Modified: 11/3/2013 3:51:13 PM
20. Writing Binary Data To Files
C#
20 / 58
// Collect information on the file to create.
FileInfo fileInfo = new FileInfo("newFile.dat");
// Create new file.
FileStream fileStream = fileInfo.Create();
// Create new binary writer.
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
// Write data.
binaryWriter.Write(23);
binaryWriter.Write(true);
binaryWriter.Write(0.4f);
// Close file stream and release all resources.
binaryWriter.Close();
21. Reading From Binary Files
C#
21 / 58
// Collect information on the file to read from.
FileInfo fileInfo = new FileInfo("newFile.dat");
// Open file for reading.
FileStream fileStream = fileInfo.OpenRead();
// Create new binary reader.
BinaryReader binaryReader = new BinaryReader(fileStream);
// Read data.
int i = binaryReader.ReadInt32();
bool b = binaryReader.ReadBoolean();
float f = binaryReader.ReadSingle();
// Close file stream and release all resources.
binaryReader.Close();
22. File Access Rights
• When opening a file, you have to request the
required access right from the underlying operating
system
• Read access
• Write access
• You can request either exclusive or non-exclusive
access rights, possibly preventing future access to
the file until you release it again
22 / 58
23. Exclusive Reading
C#
23 / 58
// Collect information on the file to read from.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Open file for exclusive reading.
FileStream fileStream = fileInfo.OpenRead();
// Create new text reader.
TextReader textReader = new StreamReader(fileStream);
24. Exclusive Reading
C#
24 / 58
// Collect information on the file to read from.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Open file for exclusive reading.
FileStream fileStream = fileInfo.Open(FileMode.Open, FileAccess.Read);
// Create new text reader.
TextReader textReader = new StreamReader(fileStream);
25. Shared Reading
C#
25 / 58
// Collect information on the file to read from.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Open file for shared reading.
FileStream fileStream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
// Create new text reader.
TextReader textReader = new StreamReader(fileStream);
26. The interface IDisposable
• Primary use of this interface is to release unmanaged
resources
• Garbage collector automatically releases the memory
allocated to a managed object when that object is no longer
used
• However, it is not possible to predict when garbage collection
will occur.
• Furthermore, the garbage collector has no knowledge of
unmanaged resources such as window handles, or open files
and streams
• Use the Dispose method of this interface to explicitly
release unmanaged resources in conjunction with the
garbage collector.
26 / 78
27. The using Statement
• Provides a convenient syntax that ensures the
correct use of IDisposable objects
• As a rule, when you use an IDisposable object,
you should declare and instantiate it in a using
statement
• Calls the Dispose method on the object in the correct
way, and causes the object itself to go out of scope as
soon as Dispose is called
• Ensures that Dispose is called even if an exception
occurs while you are calling methods on the object
• Within the using block, the object is read-only and
cannot be modified or reassigned
27 / 78
28. Writing Text To Files
C#
28 / 58
// Collect information on the file to create.
FileInfo fileInfo = new FileInfo("newFile.txt");
// Create new file.
using (FileStream fileStream = fileInfo.Create())
{
// Create new text writer.
using (TextWriter textWriter = new StreamWriter(fileStream, Encoding.UTF8))
{
// Write text.
textWriter.WriteLine("Hello World!");
}
}
29. DirectoryInfo Class
• Same as FileInfo, just for directories
• Create method
• CreateSubdirectory method
• MoveTo method
• Delete method
• Exists property
• Parent property
29 / 58
30. Enumerating Directory Files
C#
30 / 58
// Collect information on the directory to enumerate all text files of.
DirectoryInfo directoryInfo = new DirectoryInfo(".");
// Enumerate all files in the directory.
IEnumerable<FileInfo> files = directoryInfo.EnumerateFiles("*.txt");
// Show file names on console.
foreach (FileInfo file in files)
{
Console.WriteLine(file.Name);
}
31. Enumerating Directory Files
C#
31 / 58
// Collect information on the directory to enumerate all text files of.
DirectoryInfo directoryInfo = new DirectoryInfo(".");
// Recursively enumerate all files in the directory.
IEnumerable<FileInfo> files = directoryInfo.EnumerateFiles("*.txt", SearchOption.AllDirectories);
// Show file names on console.
foreach (FileInfo file in files)
{
Console.WriteLine(file.FullName);
}
32. Compressing and
Extracting Directories
C#
32 / 58
// Compress directory to zip file.
ZipFile.CreateFromDirectory("content", "archive.zip");
// Extract directory from zip file.
ZipFile.ExtractToDirectory("archive.zip", "extracted");
33. Gotcha!
To use the ZipFile class, you must
reference the assembly
System.IO.Compression.FileSystem.
33 / 78
34. Compressing and
Extracting Single Files
C#
34 / 78
const string OutputDirectory = "extracted";
if (!Directory.Exists(OutputDirectory))
{
Directory.CreateDirectory(OutputDirectory);
}
// Open zip file for reading.
using (ZipArchive archive = ZipFile.OpenRead("archive.zip"))
{
// Iterate all archive files.
foreach (ZipArchiveEntry entry in archive.Entries)
{
// Extract file.
entry.ExtractToFile(Path.Combine(OutputDirectory, entry.FullName));
}
}
35. Compositing Streams
• The design of the System.IO classes provides
simplified stream composing
• Base streams can be attached to one or more pass-
through streams that provide the functionality you
want
• Reader or writer is attached to the end of the chain
35 / 58
36. Compositing Streams
C#
36 / 58
// Collect information on the file to create.
FileInfo fileInfo = new FileInfo("newFile.gz");
// Create new file.
using (FileStream fileStream = fileInfo.Create())
{
// Create compression stream.
using (GZipStream compressionStream = new GZipStream(fileStream, CompressionMode.Compress))
{
// Create new text writer.
using (TextWriter textWriter = new StreamWriter(compressionStream))
{
// Write text.
textWriter.WriteLine("Hello World!");
}
}
}
39. Data Binding in WPF
• Allows users to view and edit data:
• Copies data from managed objects into controls, where
the data can be displayed and edited
• Ensures that changes made to data by using controls are
copied back to the managed objects
• Core unit of the data binding engine is the
Binding class
• Binds a control (the binding target) to a data object (the
binding source
39 / 58
40. Data Binding Example
XAML
40 / 58
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication1.MainWindow">
<!-- Bind the TextBox to the data source (TextBox.Text to Person.Name). -->
<TextBox Name="personNameTextBox" Text="{Binding Path=Name}" />
</Window>
41. Data Binding Example
C#
41 / 58
namespace WpfApplication1
{
public class Person
{
private string name = "No Name";
public string Name
{
get { return this.name; }
set { this.name = value; }
}
}
}
42. Data Binding Example
C#
42 / 58
namespace WpfApplication1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
// Create Person data source.
Person person = new Person();
// Make data source available for binding.
this.DataContext = person;
}
}
}
43. DataGrid Control
Provides a flexible way to display a collection of data
in rows and columns.
Rendered View
43 / 58
44. DataGrid Control
Provides a flexible way to display a collection of data
in rows and columns.
Rendered View
44 / 58
45. DataGrid Control
XAML
45 / 58
<DataGrid x:Name="TileTypeGrid" ItemsSource="{Binding}“ />
C#
List<MapTileType> tileTypes = new List<MapTileType>
{
new MapTileType(3, "Desert"),
new MapTileType(5, "Water"),
new MapTileType(1, "Grass")
};
this.TileTypeGrid.DataContext = tileTypes;
46. Updating DataGrid Controls
• Updates automatically when items are added to or
removed from the source data, if bound to a
collection that implements the
INotifyCollectionChanged interface
• Example: ObservableCollection<T>
• Automatically reflects property changes, if the
objects in the collection implement the
INotifyPropertyChanged interface
46 / 58
47. DataGrid Control Content
• Generates columns automatically
• Type of column that is generated depends on the
type of data in the column
• String: Label
• Bool: CheckBox
• Enum: ComboBox
47 / 58
48. DataGrid Control Selection
• SelectionMode property specifies whether a user
can select cells, full rows, or both
• SelectionUnit property specifies whether multiple
rows/cells can be selected, or only single rows/cells
• SelectedCells property contains cells that are
currently selected
• SelectedCellsChanged event is raised for cells for
which selection has changed
48 / 58
49. DataGrid Control Editing
• IsReadOnly property disables editing
• CanUserAddRows and CanUserDeleteRows
properties specify whether a user can add or delete
rows
• Provides BeginEdit, CommitEdit, and CancelEdit
commands
49 / 58
55. Assignment #3
1. Map Sprites
1. Create a sprite (.png file) for each of your terrain types
and add it to the project.
2. Load all sprites on startup of your application by
creating and storing BitmapImage objects. You can
access project resources in image URIs as follows:
image.UriSource = new
Uri("pack://application:,,,/Desert.png");
55 / 58
56. Assignment #3
2. Map Canvas
1. Add a canvas to your main window.
2. Reset the map canvas whenever a new map is
created:
1. Remove all children.
2. Add Image children to the canvas.
3. Set the position of these children using Canvas.SetLeft and
Canvas.SetTop.
56 / 58
58. Assignment #3
4. Brush
1. Add a brush selection to your main window.
2. Enable drawing on the map canvas.
1. Modify the map model whenever the user clicks on a map
canvas image. You can use the Tag property of an image to
store its position, and the MouseLeftButtonDown,
MouseLeftButtonUp and MouseMove events for handling user
input.
2. Update the map canvas with the new tile at the clicked
position.
58 / 58
59. References
• MSDN. WPF Controls by Category.
https://msdn.microsoft.com/en-
us/library/ms754204%28v=vs.100%29.aspx, May 2016.
• MSDN. File and Stream I/O.
http://msdn.microsoft.com/en-
us/library/k3352a4t%28v=vs.110%29.aspx, May 2016.
• MSDN. Common I/O Tasks.
http://msdn.microsoft.com/en-
us/library/ms404278%28v=vs.110%29.aspx, May 2016.
• MSDN. using Statement (C# Reference).
http://msdn.microsoft.com/en-
us/library/yh598w02(v=vs.120).aspx, May 2016.
59 / 58
61. 5 Minute Review Session
• Which different WPF data controls do you know?
• What are the three fundamental operations provided by
streams?
• Point out the difference between streams and files!
• Which namespaces and classes does .NET provide for
stream and file handling?
• What’s the point of closing a stream, and how do you do
that?
• Which types of file access rights do you know?
• Why and how are streams composited in .NET?
• What are the most common I/O exceptions in .NET?
• How do you bind data to a WPF control?
61 / 58