Module 6: Reading and Writing Local Data
Contents:
Module overview
Lesson 1: Reading and Writing Files
Lesson 2: Serializing and Deserializing Data
Lesson 3: Performing I/O by Using Streams
Lab: Generating the Grades Report
Module review and takeaways
Module overview
Reading and writing data are core requirements for many applications, such as a text file
editor saving a file to the file system, or a Windows service writing error messages to a
custom log file. The local file system provides the perfect environment for an application
to read and write such data, because access is fast and the location is readily available.
The Microsoft NET Framework provides a variety of I/O classes that simplify the
process of implementing I/O functionality in your applications.
In this module, you will learn how to read and write data by using transactional file
system I/O operations, how to serialize and deserialize data to the file system, and how to
read and write data to the file system by using streams.
Objectives
After completing this module, you will be able to:
* Read and write data to and from the file system by using file /O.* Convert data into a format that can be written to or read from a file or other data
source.
* Use streams to send and receive data to or from a file or data source
Lesson 1: Reading and Writing Files
‘The NET Framework provides the System.IO namespace, which contains a number of
classes that help simplify applications that require I/O functionality.
In this lesson, you will learn how to use the classes in this namespace to read and write
data to and from files, and to manipulate files and directories on the file system.
Lesson objectives
After completing this lesson, you will be able to:
+ Read and write data by using the File class.
+ Manipulate files by using the FileInfo and the File classes.
+ Manipulate directories by using the DirectoryInfo and Directory classes.
* Manipulate file and directory paths by using the Path class.
Reading and Writing Data by Using the File Class- The System.IO namespace contains classes for
manipulating files and directories
* The File class contains atomic read methods,
including:
+ ReadAllText(...)
+ ReadAllLines(...)
The File class contains atomic write methods,
including:
+ WriteAllText
- AppendAllText(...)
The File
use to perform transactional operations for direct reading and writing of files. These
s in the System.IO namespace exposes several static methods that you can
methods are transactional because they wrap several underlying functions into a single
method call. Typically, to read data from a file, you:
1. Acquire the file handle.
2. Opena stream to the file.
Buffer the data from the file into memory.
4. Release the file handle so that it can be reused.
The static methods that the File class exposes are convenient because they encapsulate
intricate, low-level functions. However their convenience and the fact that they shield the
developer from the underlying functionality means in some cases they don’t offer the
control or flexibility that applications require. For example, the ReadAlText method
will read the entire contents of a file into memory. For small files this will be fine, but for
large files it can present scalability issues, and may result in an unresponsive UI in your
application.Reading Data from Files
The File class provides several methods that you can use to read data from a file. The
format of your data and how your application intends to process it will influence the
method that you should use. The following list describes some of these methods:
The ReadAllText method enables you to read the contents of a file into a single string
variable. The following code example shows how to read the contents of the
settings.txt file into a string named settings
string filePath = @"C:\fourthCoffee\settings. txt’
string settings = File.ReadAl]lText(filePath) ;
The ReadAllLines method enables you to read the contents of a file and store each
line at a new index in a string array. The following code example shows how to read
the contents of the settings.txt file and store each line in the string array named
settingsLineByLine.
string filePath = @"C:\fourthCoffee\settings.txt";
string[] settingsLineByLine =
File.ReadAllLines(filePath) ;
+ The ReadAllBytes method enables you to read the contents of a file as binary data
and store the data in a byte array. The following code example shows how to read the
contents of the settings.txt file into a byte array named rawSettings.
string filePath = @"C:\fourthCoffee\settings.txt";
byte[] rawSettings = File.ReadAl1Bytes(filePath) ;
Note: During these examples and for the rest of this module, you'll see the
notation @”. Normally, when the character ‘\’ appears in a string, it’s treated
as an escape character, transforming the next character to a special Unicode orASCII character. For example, the string “\n” will be transformed to the new
line character. To write ‘\’, you need to add another to escape it, like this: "\\”.
String starting with @, called verbatim strings do not treat ‘V’ as an escape
character, and anything written in it will be treated literally. It’s especially
useful to shorten paths, negating the need for multiple “\\”.
‘You can lear more about strings here: string (C# Reference),
https://docs. microsoft.com/en-us/dotnet/csharp/language-
reference/keywords/string.
Each of these methods enables you to read the contents of a file into memory. You
could use the ReadAllText method if you wanted to cache the entire file in memory
in a single operation. Alternatively, if you wanted to process a file line-by-line, you
could use the ReadAllLines method to read each line into an array.
Writing Data to Files
The File class also provides methods that you can use to write different types of data
toa file. For each of the different types of data you can write, the File class provides
two methods:
+ Ifthe specified file does not exist, the Writexxx methods create a new file with the
new data. If the file does exist, the Writexxx methods overwrite the existing file with
the new data.
+ Ifthe specified file does not exist, the Appendxxx methods also create a new file with
the new data. However, if the file does exist, the new data is written to the end of the
existing file.
The following list describes some of these methods:
+ The WriteAllText method enables you to write the contents of a string variable to a
file. If the file exists, its contents will be overwritten. The following code example
shows how to write the contents of a string named settings to a new file named
settings.txt.
string filePath =
string settings
@"C:\fourthCoffee\settings. txt
“companyName=fourth coffee;";File.WriteAlIText(filePath, settings);
+ The WriteAllLines method enables you to write the contents of a string array to a
file. Each entry in the string array represents a new line in the file. The following code
example shows how to write the contents of a string array named hosts to a new file
named hosts.txt.
string filePath = @"C:\fourthCoffee\hosts.txt ";
string[] hosts = { "86.120.1.203", "113.45.80.31",
"168.195.23.29" };
File.WriteAllLines(filePath, hosts);
+ The WriteAIBytes method enables you to write the contents of a byte array to a
binary file. The following code example shows how to write the contents of a byte
array named rawSettings to a new file named settings.txt.
string filePath = @"C:\fourthCoffee\setting, txt
byte[] rawSettings =
{99,111,109,112,97,110,121,78,97,109,101,61,102,111,
117,114,116, 104, 32,99,111,102,102,101,101};
File.WriteAllBytes(filePath, rawSettings);
+ The AppendAllText method enables you to write the contents of a string variable to
the end of an existing file. The following code example shows how to write the
contents of a string variable named settings to the end of the existing settings.txt file.
string filePath = @"C:\fourthCoffee\settings.txt";
string settings = "companyContact= Dean Halstead";
File.AppendAllText(filePath, settings);+ ‘The AppendAllLines method enables you to write the contents of a string array to the
end of an existing file. The following code example shows how to write the contents
ofa string array named newHosts to the existing hosts.txt file
string filePath = @"C:\fourthCoffee\hosts.txt ";
string[] newHosts = { "97.11.1.195", "203.194.40.177" };
File.WriteAllLines(filePath, newHosts);
Each of these methods enables you to write data to a file. If, you want to add data to an
existing file that may already exist, then you should use an Appendxxx method. If you
want to overwrite an existing file, then you should use a Writexxx method. Then,
depending on how you want the information is stored (whether as binary data, a textual
blob in a string, or an array of strings representing each individual line) use the
sox IBytes, xxxAU Text, or xxxAllLines method.
Manipulating Files
+The File class provides static members
File.Delete(...)
bool exists = File.Exists(...):
DateTime createdOn = File.GetCreationTime(...);
- The Filelnfo class provides instance members
Fileinfo file = new FileInfo(...):
string name = file.DirectoryName;
bool exists = file.Exists,
file.Deleted,As well as reading from and writing to files, applications typically require the ability to
interact with files stored on the file system. For example, your application may need to
copy a file from the system directory to a temporary location before performing some
further processing, or your application may need to read some metadata associated with
the file, such as the file creation time. You can implement this type of functionality by
using the File and FileInfo classes.
File Manipulation by using the File Class
‘The File class provides static methods that you can use to perform basic file
manipulation. The following list describes some of these methods
+ The Copy method enables you to copy an existing file to a different directory on the
file system. The following code example shows how to copy the settings.txt file from
the C:\fourthCoffee\ directory to the C:\temp\ directory.
string sourceSettingsPath =
@"C:\fourthCoffee\settings.tx
string destinationSettingsPath =
@"C:\temp\settings.txt";
bool overwrite = true;
File.Copy(sourceSettingsPath, destinationSettingsPath,
overWrite) ;
Note: The overwrite parameter passed to the Copy method call indicates that
the copy process should overwrite an existing file if it exists at the destination
path. If you pass false to the Copy method call, and the file already exists, the
Common Language Runtime (CLR) will throw a System.10.1OException.
* The Delete method enables you to delete an existing file from the file system. The
following code example shows how to delete the existing settings.txt file.string filePath = @"C:\fourthCoffee\settings.txt
File.Delete(filePath) ;
* The Exists method enables you to check whether a file exists on the file system. The
following code example shows how to check whether the settings. txt file exists.
string filePath = @"C:\fourthCoffee\settings.txt";
bool persistedSettingsExist = File.Exists(filePath);
* The GetCreationTime method enables you to read the date time stamp that describes
when a file was created, from the metadata associated with the file. The following
code example shows how you can determine when the settings.txt file was created.
string filePath = @"C:\fourthCoffee\settings.txt
DateTime settingsCreatedOn =
File.GetCreationTime(filePath) ;
There are many other operations and metadata associated with files that you can
utilize in your applications. The FileInfo class provides access to these through a
number of instance members.
File Manipulation by using the FileInfo class
The FileInfo class provides instance members that you can use to manipulate an
le class that provides static methods for direct
existing file. In contrast to the
manipulation, the FileInfo class behaves like an in-memory representation of the
physical file, exposing metadata associated with the file through properties, and
exposing operations through methods
The following code example shows how to create an instance of the FileInfo class
that represents the settings.txt file.
Instantiating the FileInfo Classstring filePath = @"C:\fourthCoffee\settings.txt
FileInfo settings = new FileInfo(filePath) ;
After you have created an instance of the FileInfo class, you can use the properties
and methods that it exposes to interact with the file. The following list describes some
of these properties and methods:
The CopyTo method enables you to copy an existing file to a different directory on
the file system. The following code example shows how to copy the settings.txt file
from the C:\fourthCoffee\ directory to the C:\temp\ directory.
string sourceSettingsPath =
@"C:\fourthCoffee\settings. txt";
string destinationSettingsPath =
@"C:\temp\settings.txt";
bool overwrite = true;
FileInfo settings = new FileInfo(sourceSettingsPath) ;
settings.CopyTo(destinationSettingsPath, overwrite);
Note: The overwrite parameter passed to the CopyTo method call indicates
that the copy process should overwrite an existing file if it exists at the
destination path. If you pass false to the CopyTo method call, and the file
already exists, the CLR will throw a System.10.1OException.
The Delete method enables you to delete a file. The following code example shows
how to delete the settings.txt file.
string filePath = @"C:\fourthCoffee\settings. txt";
FileInfo settings = new FileInfo(filePath) ;
settings .DeleteQ;
The DirectoryName property enables you to get the directory path to the file. Thefollowing code example shows how to get the path to the settings.txt file
string filePath = @"C:\fourthCoffee\settings. txt’
FileInfo settings
= new FileInfo(filePath) ;
string directoryPath = settings.DirectoryName; //
returns C:\\fourthCoffee
* The Exists method enables you to determine if the file exists within the file system.
The following code example shows how to check whether the settings.txt file exists.
string filePath = @"C:\fourthCoffee\settings.txt";
FileInfo settings = new FileInfo(filePath) ;
bool persistedSettingsExist = settings.Exists;
+ The Extension property enables you to get the file extension of a file. The following
code example shows how to get the extension of a path returned from a method call.
string filePath =
FourthCoffeeDataService.GetDataPath();
FileInfo settings = new FileInfo(filePath) ;
string extension = settings.Extension;
+ The Length property enables you to get the length of the file in bytes. The following
code example shows how to get the length of the settings.txt file.
string filePath = @"C:\fourthCoffee\settings.txt";
FileInfo settings = new FileInfo(filePath) ;
Jong length = settings.Length;Manipulating Directories
* The Directory class provides static members
Directory.Delete(...);
bool exists = Directory. Exists
string] files = Directory.GetFiles(...),
° The Directorylnfo class provides instance
members
Directoryinfo directory = new Directoryinfol...)
string path = directory. FullName;
bool exists = directory. Exists,
FileInfof] files = directory.GetFiles();
It is a common requirement for applications to interact and manipulate the file system
directory structure, whether to check that a directory exists before writing a file or to
remove directories when running a system cleanup process. The NET Framework class
library provides the Directory and DirectoryInfo classes for such operations,
Manipulating Directories by using the Directory Class
Similar to the File class, the Directory class provides static methods that enable you to
interact with directories, without instantiating a directory-related object in your code.
‘The following list describes some of these static methods
+ The CreateDirectory method enables you to create a ne’
directory on the file
system. The following example shows how to create the C:\fourthCoffee\tempData
directory.
string directoryPath = @"C:\fourthCoffee\tempData";
Directory.CreateDirectory(directoryPath) ;+ The Delete method enables you to delete a directory at a specific path. The following
code example shows how to delete the C:\fourthCoffee\tempData directory, and all its
contents.
string directoryPath = @"C:\fourthCoffee\tempData";
bool recursivelyDeleteSubContent = true;
Directory.Delete(directoryPath,
recursivelyDeleteSubContent) ;
Note: The recursivelyDeleteSubContent parameter passed into the Delete
method call indicates whether the delete process should delete any content
that may exist in the directory. If you pass false into the Delete method call,
and the directory is not empty, the CLR will throw a
System.10.1OException.
+ The Exists method enables you to determine if a directory exists on the file system.
The following code example shows how to determine if the
C:MourthCoffee\tempData directory exists.
string directoryPath = @"C:\fourthCoffee\tempData";
bool tempDataDirectoryExists =
Directory. Exists(directoryPath) ;
+ The GetDirectories method enables you to get a list of all subdirectories within a
specific directory on the file system. The following code example shows how to get a
list of all the sub directories in the C:\fourthCoffee\tempData directory.
string directoryPath = @"C:\fourthCoffee\tempData";
string[] subDirectories =
Directory. GetDirectories(directoryPath) ;+ The GetFiles method enables you to get a list of all the files within a specific
directory on the file system. The following example shows how to get a list of all the
files in the C:\fourthCoffee\tempData directory.
string directoryPath = @"C:\fourthCoffee\tempData" ;
string[] files = Directory.GetFiles(directoryPath) ;
The DirectoryInfo class provides instance members that enable you to access
directory metadata and manipulate the directory structure.
Manipulating Directories by using the DirectoryInfo Class
The Directorylnfo class acts as an in-memory representation of a directory. Before
you can access the properties and execute the methods that the DirectoryInfo class
exposes, you must create an instance of the class.
The following code example shows how to create an instance of the DirectoryInfo
class that represents the C:\fourthCoffee\tempData directory.
Instantiating the DirectoryInfo Class
string directoryPath = @"C:\fourthCoffee\tempData";
DirectoryInfo directory = new
DirectoryInfo(directoryPath) ;
When you have created an instance of the DireetoryInfo class, you can then use its
properties and methods to interact with the directory. The following list describes
some of these properties and methods:
+ The Create method enables you to create a new directory on the file system, The
following example shows how to create the C:\fourthCoffee\tempData directory,
string directoryPath = @"C:\fourthCoffee\tempData";
DirectoryInfo directory = newDirectoryInfo(directoryPath) ;
directory.Create();
+ The Delete method enables you to delete a directory at a specific path. The following
code example shows how to delete the C:\fourthCoffee\tempData directory, and all its
contents.
string directoryPath = @"C:\fourthCoffee\tempData” ;
bool recursivelyDeleteSubContent = true;
DirectoryInfo directory = new
DirectoryInfo(directoryPath) ;
directory.Delete(recursivelyDeleteSubContent) ;
Note: The recursivelyDeleteSubContent parameter passed to the Delete
method call indicates whether the delete process should delete any content
that may exist in the directory. If you pass false to the Delete method call, and
the directory is not empty, the CLR will throw a System.10.1OException.
+ The Exists property enables you to determine if a directory exists on the file system.
The following code example shows how to determine if the
CafourthCoffee\tempData directory exists.
string directoryPath = @"C:\fourthCoffee\tempData";
DirectoryInfo directory = new
DirectoryInfo(directoryPath) ;
bool tempDataDirectoryExists = directory.Exists;
+ The FullName property enables you to get the full path to the directory. The
following example shows how to get the full path to the tempData directory.string directoryPath = @"C:\fourthCoffee\tempData";
DirectoryInfo directory = new
DirectoryInfo(directoryPath) ;
string fullPath = directory.FullName;
The GetDirectories method enables you to get a list of all subdirectories within a
ile.GetDit
method, this instance method returns an array of type DirectoryInfo, which enables
specific directory on the file system. In contrast to the static ectories
you to use each of the instance properties for each subdirectory. The following code
example shows how to get all of the sub directories in the C:\fourthCoffee\tempData
directory.
string directoryPath = @"C:\fourthCoffee\tempData";
DirectoryInfo directory = new
DirectoryInfo(directoryPath) ;
DirectoryInfo[] subDirectories =
directory.GetDirectoriesQ;
The GetFiles method enables you to get a list of all the files within a specific
‘etFiles method, this
instance method returns an array of type FileInfo, which enables you to use each of
directory on the file system, In contrast to the static F
the instance properties for each file. The following example shows how to get all of
the files in the C:\fourthCoffee\tempData directory.
string directoryPath = @"C:\fourthCoffee\tempData";
DirectoryInfo directory = new
DirectoryInfo(directoryPath) ;
FileInfo[] subFiles = directory.GetFilesQ;Depending on whether you require a simple one-line-of-code approach to manipulate a
directory, or something that offers slightly more flexibility, either the static Directory or
instance DirectoryInfo class should fulfill your requirements.
Manipulating File and Directory Paths
The Path class encapsulates file system utility
functions
string settingsPath ="..could be anything here..";
// Check to see if path has an extension.
bool hasExtension = Path.HasExtension(settingsPath),
// Get the extension from the path.
string pathExt = Path.GetExtension(settingsPath);
// Get path to temp file.
string tempPath = Path.GetTempFileName();
// Returns C.\Users\LeonidsP\ AppData\Local\Temp\ABC.tmp
All files and all directories have a name, which when combined to point to a file ina
directory, constitute a path. Different file systems can have different conventions and
which
encapsulates a variety of file system utility functions that you can use to parse and
rules for what constitutes a path. The NET Framework provides the Path cl.
construct valid file names, directory names, and paths within the Windows file system.
These functions can be useful if your application needs to write a file to a temporary
location, extract an element from a file s
stem path, or even generate a random file
name.
The following code shows how to create a new directory on the root of the C:
Creating a Temporary Directory the Hard Waystring tempDirectoryPath = @"C:\fourthCoffee\tempData
if (!Directory.Exists(tempDirectoryPath))
Directory.CreateDirectory(tempDirectoryPath) ;
Howe’
er, with the above approach, you are making many assumptions, including
whether your application has the necessary privileges to perform I/O at the root of the C
drive, and whether the C drive actually exists.
A better way is to use the static GetTempPath method provided by the Path class to get
the path to the current user's Windows temporary directory.
Getting the Path to the Windows Temporary Directory
string tempDirectoryPath = Path.GetTempPathQ) ;
The Path class includes many other statie methods that provide a good starting point for
any custom I/O type functionality that your application may require. These methods
include the following:
+ The HasExtension method enables you to determine if the path your application is
processing has an extension. This provides a convenient way for you to determine if
you are processing a file or a directory. The following example shows how to check
whether the path has an extension.
string settingsPath = "..could be anything here..";
bool hasExtension = Path.HasExtension(settingsPath) ;
+ The GetExtension method enables you to get the extension from a file name. This,
method is particularly useful when you want to ascertain what type of file your
application is processing. The following code example shows how to check whether
the settingsPath variable contains a path that ends with the .txt extension.string settingsPath = "..could be anything here.
string pathExt = Path.GetExtension(settingsPath) ;
if (pathext == ".txt")
{
// More processing here.
The GetTempFileName enables you to create a new temp file in your local Windows
temporary directory in a single transactional operation folder. This method then
returns the absolute path to that file, ready for further processing. The following code
shows how to invoke the GetTempFileName method.
string tempPath = Path.GetTempFileName() ;
// Returns C:\Users\LeonidsP\AppData\Local\Temp\ABC. tmp
Additional Reading: For more information about the Path class, refer to the
Path Class page at
https//aka.ms/moc-20483c-m6-pgl.
Demonstration: Manipulating Files, Directories, and Paths
In this demonstration, you will use the File, Directory, and Path classes to build a utility
that combines multiple files into a single file.
Demonstration steps
You will find the steps in the Demonstration: Manipulating Files, Directories, and
Paths section on the following page: https://github.com/MicrosoftLearning/20483-
Programming-in-C-Sharp/blob/master/Instructions/20483C_MOD06_DEMO.md.
Lesson 2: Serializing and Deserializing DataSerialization is the process of converting data to a format that can be persisted or
transported. Deserialization is the process of converting serialized data back to objects.
In this lesson, you will learn how to serialize objects to binary, XML, and JavaScript
Object Notation (JSON), and how to create a custom serializer so that you can serialize
objects into any format you choose.
Lesson objectives
After completing this lesson, you will be able to:
+ Describe the purpose of serialization, and the formats that the .NI
Framework
supports.
+ Create a custom type that is serializable.
+ Serialize an object as binary.
+ Serialize an object as XML.
+ Serialize an object as JSON.
+ Create a custom serializer by implementing the IFormatter interface.
What Is Serialization?Binary
1010101010101111101011010101011010111111101010110110001
°XML
- JSON
{
“ConfigName”:"FourthCoffee_Default",
“DatabaseHostName" “database209.fourthcoffee.com"
}
Applications typically process data. Data is read into memory, pethaps from a file or web
servic!
II, pro
ssed, and then passed to another component in the system for further
processing. The components of a system may run on the same machine, but commonly
components run on different platforms, on different hardware, and even in different
geographical locations. The format of the data also needs to be lightweight so that it can
be transported over a variety of protocols, such as HTTP or SOAP. Serialization is the
process of converting the state of an object into a form that can be persisted or
transported.
‘ializable Formats
The requirements of your system, and how you intend to transport the data, will
influence the serialization format you choose, The following table describes some of the
common formats available.Description
F
°
r
m
a
t
B__ Serializing data into the machine-readable binary format enables you to preserve the fidelity and state of
in an object between different instances of your application, Binary serialization is also fast and lightweight,
ar because the binary format does not require the processing and storage of unnecessary formatting
y constructs
Binary serialization is commonly used when persisting and transporting objects between applications
running on the same platform,
Binary Example
100000010111010001101110010101110001111111010111000110011001011011100
111100101101010010000100001101100010000000001111000001110001100000100
(000011000100101010001110110010110100001110010100010110101010011111101
110101100001101011001101110110100100001111010100111100000101101111111
010111000110011001011011100111100101101010010000100001101100010000000
(001111000001110001100000100000011000100101010001110110010110100001110
010100010110101010011111101110101000110000010000001100010010101000111
011001011010000
»
Serializing data into the XML format enables you to utilize an open standard that can be processed by any
M__ application, regardless of platform. In contrast to binary, XML does not preserve type fidelity; it only lets
L__ you serialize public members that your type exposes.
The XML format is more verbose than binary, as the serialized data is formatted with XML constructs,
‘This makes the XML format less efficient and more processor intensive during the serializing,
deserializing, and transporting processes.
However, the nature of XML as a plain text and free-form language allows messages to be transmitted
across different applications and platforms, So long as the transmitter and receiver have agreed on a
known contract, both can send and receive messages and convert them to the appropriate model within
their respective environments.XML serialization was commonly used to serialize data that can be transported via the SOAP protocol to
and from web services. However, due to SOAP’s verbose and strict nature, this protocol has fallen out of
favor, and is generally found today only in legacy environments,
SOAP XML Example
FourthCoffee Default
database209. fourthcoffee.com
C:\fourthcoffee\applicationdata\,
Serializing data into the ISON format enables you to utilize a lighowei
, data-interchange format that is
S__ based on a subset of the JavaScript programming language. JSON is a simple text format that is human
readable and also easy to parse by machine, irrespective of platform.
Zo
{ISON shares XML strengths as plain text and free form, making it eross platform. However, unlike XML,
it has a much more concise syntax, which makes it cheaper to transmit and human readable. These
advantages made JSON the prevalent language to transmit data today, and the de-facto standard in today's
industry.
JSON is commonly used to transport data between everything from Asynchronous JavaScript and XML
(AJAX) calls to messages between webservices, because unlike SOAP, you are not limited to just
communicating within the same domain,
JSON Example
{
"ConfigName”:"FourthCoffee_Default",
"DatabaseHostName" : "database209. fourthcoffee. com",
“ApplicationDataPath":"C:\\fourthcoffee\\applicationdata\\"
+
“ramework
Alternatively, if you want to serialize your data to a format that the NET
does not natively support, you can implement your own custom serializer class.Creating a Serializable Type
Implement the ISerializable interface
[Serializable]
public class ServiceConfiguration - ISerializable
{
public ServiceConfiguration(
Serializationinfo info, StreamingContext ctxt)
{
a
public void GetObjectData(
Serializationinfo info, StreamingContext context)
‘The NET Framework provides many classes that are serializable. If you want to create
your own types that are serializable, you need to ensure that the type definition incudes
the nes
ssary configuration and functionality for the serilalizer to consume, The NET
Framework provides the System and System.Runtime.Serialization namespaces, which
provide classes to enable serialization support.
To create a serializable type, perform the following steps:
1. Define a default constructor.
public class ServiceConfiguration
{
public ServiceConfigurationQ { we}
2. Decorate the class with the Serializable attribute provided in the System
namespace.[Serializable]
public class ServiceConfiguration
{
Implement the Serializable interface provided in the
tion namespace. The GetObjectData method enables
System.Runtime.Seri:
you to extract the data from your object during the serialization process.
[Serializable]
public class ServiceConfiguration : ISerializable
{
public void GetObjectData(SerializationInfo info,
StreamingContext context) { wae }
3
Define a deserialization constructor, which accepts SerializationInfo and
StreamingContext objects as parameters. This constructor enables you to
rehydrate your object during the deserialization process.
[Serializable]
public class ServiceConfiguration : ISerializable
{
public ServiceConfiguration(SerializationInfo info,
}
StreamingContext ctxt) {
35. Define the public members that you want to serialize. You can instruct the
serializer to ignore private fields by decorating them with the NonSerialized
attribute.
[NonSerial ized]
private Guid _internalId;
public string ConfigName { get; set; }
public string DatabaseHostName { get; set; }
public string ApplicationDataPath { get; set; }
‘The following code example shows the complete ServiceConfiguration class, which is
serializable by any of the NET Framework IFormatter implementations.
Serializable Type
[Serializable]
public class ServiceConfiguration : ISerializable
{
[NonSerialized]
private Guid _internalId;
public string ConfigName { get; set; }
public string DatabaseHostName { get; set; }
public string ApplicationDataPath { get; set; }
public ServiceConfiguration()
{+
public ServiceConfiguration(SerializationInfo info,
StreamingContext ctxt)
{
this.ConfigName
= info.GetValue("ConfigName",
typeof (string)) .ToStringQ);
this.DatabaseHostName
= info.GetValue("DatabaseHostName",
typeof (string)) .ToStringQ ;
this. ApplicationDataPath
= info.GetValueC"ApplicationDataPath",
typeof (string)) .ToString();
}
public void GetObjectData(SerializationInfo info,
StreamingContext context)
{
info.AddValue("ConfigName", this.ConfigName) ;
info.AddValue("DatabaseHostName",
this.DatabaseHostName) ;
info. AddValue("ApplicationDataPath",
this.ApplicationDataPath) ;
+
Serializing Objects as Binary+ Serialize as binary
ServiceConfiguration config = ServiceConfiguration.Default;
IFormatter formatter = new BinaryFormatter(),
FileStream buffer = File.Create("C: \ \fourthcoffee \ \config.txt");
formatter. Serialize(buffer, config)
buffer.Close();
+ Deserialize from binary
IFormatter formatter = new BinaryFormatter():
FileStream buffer = File, OpenRead("C:\ \ fourthcoffee\ \ config. txt”)
ServiceConfiguration config
= formatter.Deserialize(buffer) as ServiceConfiguration,
buffer.Closed,
in the
System.Runtime Serialization. Formatters.Binary namesp
The .NET Framework provides the BinaryFormatter cl:
which you can use to
serialize and deserialize objects as binary.
Note: The BinaryFormatter and SoapFormatter classes implement the
IFormatter interface. You can also implement the IFormatter interface to
create your own custom serializer.
Serialize an Object by Using the BinaryFormatter Class
To serialize an object by using the BinaryFormatter class, perform the following steps:
1. Obtain a reference to the object you want to serialize.
2. Create an instance of the BinaryFormatter that you want to use to serialize your
type.
3. Create a stream that you will use as a buffer to store the serialized data.
4. Invoke the BinaryFormatter.Serialize method, passing in stream that the
serialized data will be buffered to, and the object you want to serialize.The following code example shows how to use the BinaryFormatter class to serialize
an object as binary.
BinaryFormatter Serialize Example
// Create the object you want to serialize.
ServiceConfiguration config =
ServiceConfiguration.Default;
// Create the formatter you want to use to serialize the
object.
IFormatter formatter = new BinaryFormatter();
// Create the stream that the serialized data will be
buffered to.
FileStream buffer =
File.Create(@"C:\fourthcoffee\config.txt") ;
// Invoke the Serialize method.
formatter .Serialize(buffer, config);
// Close the stream.
buffer.CloseQ;
This example, serializes the ServieeConfiguration object, and writes the serialized data
to a file. It is important to note that serialization doesn’t just imply writing data to a file.
Serialization is the process of transforming a type into another format, which you ean
then write to a file or database, or send over HTTP to a web service.
Deserialize an Object by Using the BinaryFormatter Class
Deserializing is the process of transforming your serialized object back into a format that
your application can process. To deserialize an object by using the BinaryFormatter
class, perform the following steps:
1. Create an instance of the BinaryFormatter that you want to use to deserializeyour type.
2. Create a stream to read the serialized data.
3. Invoke the BinaryFormatter.Deserialize method, passing in stream that contains
the serialized data.
4. Cast the result of the BinaryFormatter.Deserialize method call into the type of
object that you are expecting.
‘The following code example shows how to use the BinaryFormatter class to deserialize
binary data to an object.
BinaryFormatter Deserialize Example
// Create the formatter you want to use to serialize the
object.
IFormatter formatter = new BinaryFormatter();
// Create the stream that the serialized data will be
buffered too.
FileStream buffer =
File.OpenRead(@"C:\fourthcoffee\config. txt");
// Invoke the Deserialize method.
ServiceConfiguration config =
formatter.Deserialize(buffer) as ServiceConfiguration;
// Close the stream,
buffer. CloseQ;
‘The above example reads the serialized binary data from a file, and then deserializes the
binary into a ServiceConfiguration object. The process is the same for serializing and
deserializing objects by using any formatters that implement the [Formatter interface.
This includes the SoapFormatter class, and any custom formatters that you may
implement.Serializing Objects as XML
+ Serialize as XML
ServiceConfiguration config = ServiceConfiguration.Default
IFormatter formatter = new SoapFormatter0:
FileStream buffer = File.Create(@"C: \fourthcoffee\config.xml");
formatter.Serialize(buffer, contig),
buffer.Closed,
+ Deserialize from XML
IFormatter formatter = new SoapFormatter(),
FileStream buffer = File.OpenRead(@"C: \fourthcoffee\config.xml");
ServiceConfiguration config
= formatter.Deserialize(buffer) as ServiceConfiguration;
buffer.CloseQ;
The .NET Framework provides the SoapFormatter class in the
System Runtime.Serialization.Formatters.Soap namespace, which you can use to
serialize and deserialize objects as XML.
Serialize an Object by Using the SoapFormatter Class
The proce:
for serializing data as XML is similar to the process of serializing to binary,
with the exception that you use the SoapFormatter class.
The following code example shows how to use the SoapFormatter class to serialize an
object as XML.
Soap Formatter Serialize Example
// Create the object you want to serialize.
ServiceConfiguration config =
ServiceConfi guration.Default;// Create the formatter you want to use to serialize the
object.
IFormatter formatter = new SoapFormatter();
// Create the stream that the serialized data will be
buffered too.
FileStream buffer =
File.Create(@"C:\fourthcoffee\config.xm1");
// Invoke the Serialize method.
formatter.Serialize(buffer, config);
// Close the stream.
buffer.CloseQ);
Deserialize an Object by Using the SoapFormatter Class
The process for deserializing data from XML to an object is identical to the process of
deserializing binary data, with the exception that you use the SoapFormatter class.
The following code example shows how to use the SoapFormatter class to deserialize
XML data to an object.
SoapFormatter Deserialize Example
// Create the formatter you want to use to serialize the
object.
IFormatter formatter = new SoapFormatter() ;
// Create the stream that the serialized data will be
buffered too.
FileStream buffer =
File.OpenRead(@"
// Invoke the Deserialize method.
:\fourthcoffee\config. xml");
ServiceConfiguration config =
formatter .Deserialize(buffer) as ServiceConfiguration;// Close the stream.
buffer.CloseQ;
Serializing Objects as JS‘
+ Serialize as JSON
ServiceConfiguration config = ServiceConfiguration.Default,
DataContractJsonserializer jsonSerializer
= new DataContract}sonSerializer(config.GetType0):
FileStream buffer = File.Create(@"C:\ fourthcoffee \config.txt’)
jsonserializer.WriteObject(buffer, contig):
buffer.Closed,
+ Deserialize from JSON
DataContract)sonSerializer jsonSerializer = new
DataContract}sonSerializer(
typeof(ServiceConfiguration)),
FileStream buffer = File-OpenRead(@"C: \fourthcoffee\ config.txt’),
ServiceConfiguration config = jsonSerializer.ReadObject(buffer)
as ServiceConfiguration;
buffer.CloseQ);
The .NET Framework also supports serializing objects as JSON by using the
DataContractJsonSerializer class in the System.Runtime.Serialization.Json
namespace. The JSON serialization steps are different because the
DataContractJsonSerializer class is deri
-d from the abstract XmlObjectSerializer
class, and it is not an implementation of the [Formatter interface.
Serialize an Object by Using the DataContractJsonSerializer Class
To serialize an object by using the DataContractJsonSerializer class, perform the
following steps:
1. Obtain a reference to the object that you want to serialize.
2. Create an instance of the DataContractJsonSerial
zer class that you want to useto serialize your type. The constructor also requires you to pass in a Type object,
representing the type of object you want to serialize
3. Create a stream that you will use as a buffer to store the serialized data.
4. Invoke the DataContractJsonSerializer: WriteObject method, passing in stream
that the serialized data will be buffered too, and the object you want to serialize.
The following code example shows how to use the DataContractJsonSerializer class to
serialize an object as JSON.
DataContractJsonSerializer Serialize Example
// Create the object you want to serialize.
ServiceConfiguration config =
ServiceConfiguration.Default;
// Create a DataContractJsonSerializer object that you
will use to serialize the
// object to JSON.
DataContractJsonSerializer jsonSerializer
= new DataContractJsonSerializer(config.GetType());
// Create the stream that the serialized data will be
buffered too.
FileStream buffer =
File.Create(@"C:\fourthcoffee\config.txt") ;
// Invoke the WriteObject method.
jsonSerializer.WriteObject(buffer, config);
// Close the stream.
buffer.CloseQ;
Deserialize an Object by using the DataContractJsonSerializer ClasssonSerializer clas:
To deserialize JSON to an object by using the DataContrae
perform the following steps:
1. Create an instance of the DataContractJsonSerializer class that you want to use
to serialize your type. The constructor also requires you to pass in a Type object,
representing the type of object you want to deserialize.
2. — Create a stream that will read the serialized JSON into memory.
Invoke the DataContractJsonSerializer.ReadObject method, passing in the
stream that contains the serialized data.
4. — Cast the result of the DataContractJsonSerializer.ReadObject method call into
the type of object you are expecting.
The following code example shows how to use the DataContractJsonSerializer class to
deserialize JSON data to an object.
DataContractJsonSerializer Deserialize Example
// Create a DataContractJsonSerializer object that you
will use to
// deserialize the JSON.
DataContractJsonSerializer jsonSerializer
= new
DataContractJsonSerializer (typeof (ServiceConfiguration));
// Create a stream that will read the serialized data.
FileStream buffer =
File.OpenRead(@"C:\fourthcoffee\config. txt") ;
// Invoke the ReadObject method.
ServiceConfiguration config =
jsonSerializer.ReadObject(buffer) as ServiceConfiguration;
// Close the stream.
buffer.CloseQ;Serializing Objects as JSON by Using JSON.Net
+ Serialize as JSON
|| Create the object you want to serialize.
ServiceConfiguration config = ServiceConfiguration.Default;
/{ Serialize the object to a string
var jsonString = JsonConvert.Serialize(config),
+ Deserialize from JSON
/| Deserialize to the desired type
var deserializedConfig =
JsonConvert.DeserializeObject (sonstring)
While the NET framework provides the built in DataContractJsonSerializer class to
serialize objects to JSON, today’
ndard of using JSON in the NET environment is
Newtonsoft’s Json.NET library. Json.NET provides an expansive library to create and
is their JsonConvert class that can
query JSON. Most important for our purpos:
serialize and deserialize classes to and from JSON
‘To use the Json.Net library, you'll need to add it to your project by using Nuget, which
is a package manager for .Net, allowing you to easily download and manage third party
libraries in your project.
1. In Solution Explorer, right-click the project.
2. — Select Manage Nuget Packages.
Select the Browse tab and search for JSON.
4. Select the Newtonsoft.Json package, and then click Install.Unlike the .NET implementations of the IFormatter interface, JsonConvert doesn’t
require the data class to be decorated with the Serializable attribute. Any class can be
converted to JSON without special treatment. However, Json.NET does provide a set of
attributes to specify exactly how the model will be serialized, if necessary. The most
useful of them is perhaps the JsonProperty attribute, which allows to determine the
name of the property in the serialized JSON string. Unlike Visual C#, JSON’s naming
standard for properties can vary, and usually follow the lowerCamelCase, snake_case, or
even the kebab-case convention, This feature can be very useful, especially when
communicating with other applications.
A normal data object ready to be used with JsonConvert can look something like this:
The following code example shows the complete ServiceConfiguration class, ready to
be serialized with Json.Net.
JSON Serializable Type
public class ServiceConfiguration
{
// JsonConvert ignores private members by default
private Guid _internalld;
// Map the properties with json naming conventions
[JsonProperty(“configName”)]
public string ConfigName { get; set; }
[JsonProperty(“databaseHostName”)]
public string DatabaseHostName { get; set; }
[JsonProperty(“applicationDataPath”)]
public string ApplicationDataPath { get; set; }
Serialize an Object by Using the JsonConvert Class
To serialize an object by using the JsonConvert class, perform the following steps1. Obtain a reference to the object that you want to serialize.
2. Invoke the JsonConvert Serialize method. The method will automatically infer
the type processed, and serialize it accordingly.
The following code example shows how to use the JsonConvert class to serialize an
object as SON.
JsonConvert Serialize Example
// Create the object you want to serialize.
ServiceConfiguration config =
ServiceConfiguration.Default;
var jsonString = JsonConvert.Serialize(config);
Deserialize an Object by Using the JsonConvert Class
To deserialize JSON to an object by using the JsonConvert class, perform the following
steps:
1. Obtain the JSON string you need to deserialize
2. Invoke the JsonConvert.Desrialize method, passing in the string to be
deserialized, as well as the target type as a generic type parameter.
The following code example shows how to use the JsonConvert class to deserialize
JSON data to an object.
JsonConvert Deserialize Example
// Get the JSON string - Here we’re assuming it’s the same
from the previous example.// Deserialize to the desired type
var deserializedConfig
JsonConvert .DeserializeObject
(jsonString);
You might have noticed that unlike the previous topics, here we're serializing directly to
a string, and not to a stream, and then to a file. You will find that most messages passed
along are small enough not to warrant the use of a stream and saving them to a string is
perfectly acceptable. Modern computers are powerful enough to handle quite large
strings.
However, Json.Net allows serializing to and from streams very similarly to the internal
Net types, while still allowing to discard the ISerializable interface, and keeping
Json.Net’s lax usage of its attributes.
Serialize an Object by Using the JsonSerializer Class
To serialize an object by using the JsonSerializer class, perform the following steps:
1. Obtain a reference to the object that you want to serialize.
2. — Create an instance of the JsonSerializer class that you want to use to serialize your
type.
Create a stream writer to write the object.
4. Invoke the JsonSerializer.Serialize method, passing in the stream writer that the
serialized data will be buffered too, and the object you want to serialize. The
method will automatically infer the type processed and will serialize it accordingly.
‘The following code example shows how to use the JsonSerializer class to serialize an
object as JSON and save it to a file.
JsonSerializer Serialize Example// Create the serializer
var serializer = new JsonSerializerQ);
// Open the stream to the file
var fileWriter =
File.CreateText (@"C:\fourthcoffee\config. json”
// Serialize and write the object to the file
serializer.Serialize(filewriter, config);
// Close the stream
fileWriter.CloseQ;
fileWriter.DisposeQ;
Deserialize an Object by Using the JsonSerializer Class
To deserialize JSON to an object by using the JsonSerializer class, perform the
following steps:
1. Create an instance of the JsonSerializer class that you want to use to serialize your
type.
2. Create a stream, stream reader, and JsonTextReader that will read the serialized
JSON into the memory.
3. Invoke the JsonSerializer.Deserialize method, passing in the
JsonTextReader that contains the serialized data, as well as the target type as a
generic type parameter.
4. — Close all the readers and stream.
‘The following code example shows how to use the JsonSerializer class to deserialize
JSON data to an object.
JsonSerializer Deserialize Example// Create the serializer
var serializer = new JsonSerializerQ;
// Open a stream to the file
var fileReader =
Fi le.OpenRead(@"C:\fourthcoffee\config. json
// Create a stream and json text readers
var textReader = new StreamReader(fileReader);
var jsonReader = new JsonTextReader(textReader) ;
// Deserialize to the desired type
var deserializedConfig =
serializer.Deserialize(jsonReader) ;
// Close all the readers and the stream
jsonReader.Close();
textReader.Close();
textReader.Dispose();
fileReader.Close();
fileReader.DisposeQ;
Additional Reading: For more information about the Json.Net library, you can
turn to the following resources:
Json.Net home page: bps //aka.ms/moc-20483c-m6-pg2
Demonstration: Serializing Objects as JSON using JSON.Net
In this demonstration, you will see how to serialize and deserialize objects using
JSON.NET.
Demonstration stepsCreating a Custom Serializer
Implement the IFormatter interface
class IniFormatter : |Formatter
{
public ISurrogateSelector SurrogateSelector { get; set; }
public SerializationBinder Binder { get; set; }
public StreamingContext Context { get; set; }
public object Deserialize(Stream serializationStream)
{
}
public void Serialize(Stream serializationStream, object graph)
You may want to serialize data into a format other than binary, XML, or JSON. The
NET Framework provides the [Formatter interface in the
system.Runtime.Serial
ation namespace, so you can create your own formatter. Your
custom formatter will then follow the same pattern as the BinaryFormatter and
SoapFormatter classes.
To create your own formatter, perform the following steps:
1. Create a class that implements the [Formatter interface.
nv
Create implementations for the SurrogateSelector, Binder, and Context
properties.
Create implementations for the Deserialize and Serialize methods.The following code example shows a custom formatter that can serialize and deserialize
objects to the .ini format.
Custom IniFormatter
using System;
using System.Collections.Generic;
using System. 10;
using System.Reflection;
using System.Runtime. Serialization;
namespace FourthCoffee.Serializer
{
class IniFormatter : IFormatter
{
static readonly char[] _delim = new char[] { '=" };
public ISurrogateSelector SurrogateSelector { get;
set; }
public SerializationBinder Binder { get; set; }
public StreamingContext Context { get; set; }
public IniFormatter()
{
this.Context
= new
StreamingContext (StreamingContextStates.A11);
}
public object Deserialize(Stream
serializationStream)
{
StreamReader buffer
= new StreamReader(serializationStream) ;
// Get the type from the serialized data.
Type typeToDeserialize = this.GetType(buffer) ;// Create default instance of object using type
name.
Object obj
FormatterServices.GetUninitializedObject(typeToDeserializ
2);
// Get all the members for the type.
MemberInfo[] members
FormatterServices.GetSerializableMembers(obj.GetType(Q),
this.Context) ;
// Create dictionary to store the variable names
and any serialized data.
Dictionary serializedMemberData
= new DictionaryQ;
// Read the serialized data, and extract the
variable names
// and values as strings.
while (buffer.Peek() >= 0)
{
string line = buffer.ReadLineQ;
string[] sarr = line.Split(_delim);
// key = variable name, value = variable
value.
serializedMemberData.Add(
sarr[0].TrimQ, // Variable name.
sarr[1].TrimQ); // Variable value.
}
// Close the underlying stream.
buffer.CloseQ);
// Create a list to store member values as their
correct type.List