In this article, we will complete our book management application by adding file handling features to save book information to a file and load it again when needed. This addition will make our application far more practical, allowing it to persist data across different runs.
We will continue to use the System.IO
namespace, focusing on writing and reading text files using classes such as File
, StringBuilder
, and StreamReader
. By saving our book data in a structured format, we can ensure that each entry is easily accessible and modifiable later.
Step 1: Setting Up Directory Path and File Name
Before adding the methods for saving and loading, we need to specify the path where the book data will be stored. In our Utilities.cs file, we will define two static fields to store the directory and file name:
private static string directoryPath = @"D:\data\BookManagementApp";
private static string fileName = "books.txt";
Example for directoryPath
:
- The
directoryPath
points to where the file should be saved. For this example, we are using@"D:\data\BookManagementApp"
. -
Note: You can change this path to something more convenient, such as
@"C:\BookAppData"
or@"C:\Users\YourName\Documents\BookData"
. - Ensure that the specified directory exists or can be created by the application if it does not.
Step 2: Writing Data to a File - Implementing SaveBooksToFile
To save the list of books to a file, we need to write a method that converts the list into a structured text format. Each book entry will be written as a line of text, with properties like title, author, genre, and publication date separated by a delimiter (e.g., a semicolon).
When to Write SaveBooksToFile
: Implement this method when you want to ensure that all book data can be saved for future sessions. This method should be called after registering books (option 1
in our menu).
Here is the implementation of SaveBooksToFile
:
public static void SaveBooksToFile(List<Book> books)
{
string filePath = $"{directoryPath}\\{fileName}";
// Using StringBuilder to concatenate all the book information into a single string.
StringBuilder sb = new StringBuilder();
foreach (var book in books)
{
// Convert each book into a string representation.
sb.Append($"Title:{book.Title};Author:{book.Author};Genre:{book.Genre};PublicationDate:{book.PublicationDate:yyyy-MM-dd}\n");
}
// Write the concatenated book data to the file.
File.WriteAllText(filePath, sb.ToString());
Console.WriteLine("Books saved to file successfully.");
}
Explanation
-
StringBuilder for Concatenation: Since we will be concatenating multiple strings (book details), we use
StringBuilder
for efficient memory usage. -
String Representation: Each book’s data is appended to
StringBuilder
in a structured format, with properties separated by a semicolon. -
Writing to File: Finally,
File.WriteAllText()
is used to write the entire string to the specified file. If the file already exists, it will be overwritten.
Example Use: This method should be called when the user selects option 3
in the menu to save all book data.
Step 3: Reading Data from a File - Implementing LoadBooksFromFile
We also need a way to load the book data back into memory from the file. This ensures that the books saved in previous sessions are accessible when the application starts again.
When to Write LoadBooksFromFile
: Implement this method to load data back into memory at the start of the application or whenever the user selects to load existing data (option 4
).
Here is the implementation of LoadBooksFromFile
:
public static void LoadBooksFromFile(List<Book> books)
{
string filePath = $"{directoryPath}\\{fileName}";
// Check if the file exists
if (!File.Exists(filePath))
{
Console.WriteLine("No book data file found to load.");
return;
}
// Clear existing books in memory
books.Clear();
// Reading all lines from the file
string[] booksAsStrings = File.ReadAllLines(filePath);
foreach (string bookAsString in booksAsStrings)
{
string[] parts = bookAsString.Split(';');
if (parts.Length == 4)
{
string title = parts[0].Split(':')[1];
string author = parts[1].Split(':')[1];
string genre = parts[2].Split(':')[1];
DateTime publicationDate = DateTime.Parse(parts[3].Split(':')[1]);
Book book = new Book(title, author, genre, publicationDate);
books.Add(book);
}
}
Console.WriteLine("Books loaded from file successfully.");
}
Explanation
-
File Existence Check: Before attempting to load data, we check if the file exists using
File.Exists()
. If it doesn’t, we simply return. - Clearing Current Data: We clear the current list of books to avoid duplications when loading from the file.
-
Reading the File: We use
File.ReadAllLines()
to read all the lines in the file into an array. Each line represents a book. - Parsing the String: We split each line by the semicolon delimiter to extract each property, and then split further by the colon to get the actual value.
-
Creating and Adding Book Objects: With the extracted values, we create new
Book
objects and add them to the list.
Example Use: This method should be called at the beginning of the application to load any previously saved data, or when the user selects option 4
.
Step 4: Adding Methods to the Main Program
We need to update our Program.cs file to include options for saving and loading books:
switch (userSelection)
{
case "1":
Utilities.RegisterBook(books);
break;
case "2":
Utilities.ViewBooks(books);
break;
case "3":
Utilities.SaveBooksToFile(books); // Save books to file
break;
case "4":
Utilities.LoadBooksFromFile(books); // Load books from file
break;
case "9":
running = false;
break;
default:
Console.WriteLine("Invalid selection, please try again.");
break;
}
Example Run
Imagine registering two books in the application:
-
Book 1:
- Title: "C# in Depth"
- Author: "Jon Skeet"
- Genre: "Programming"
- Publication Date: "2019-03-19"
-
Book 2:
- Title: "Clean Code"
- Author: "Robert C. Martin"
- Genre: "Software Engineering"
- Publication Date: "2008-08-01"
After registering, selecting option 3
saves both books to a file. The file would contain:
Title:C# in Depth;Author:Jon Skeet;Genre:Programming;PublicationDate:2019-03-19
Title:Clean Code;Author:Robert C. Martin;Genre:Software Engineering;PublicationDate:2008-08-01
After restarting the application, selecting option 4
would reload these books into memory, allowing you to continue managing them.
Notes on Directory Path
- The value for
directoryPath
can be modified to suit your needs:- If you are working on a Windows machine, using a path like
@"C:\BookAppData"
can make it easier to locate and manage the data. - Ensure the application has permission to create directories in the specified location.
- The
CreateDirectory()
method in ourCheckForExistingBookFile()
ensures the directory is created if it does not already exist.
- If you are working on a Windows machine, using a path like
Conclusion
In this article, we completed our book management application by adding file handling capabilities:
-
Saving Data: We implemented the
SaveBooksToFile()
method to write all book data to a text file, ensuring data is not lost between application runs. -
Loading Data: We implemented the
LoadBooksFromFile()
method to read data back into memory when the application starts, restoring the previously saved state.
This file handling functionality makes our book management tool more useful in real-world scenarios where data persistence is important. We used the System.IO
namespace to achieve this and worked with text files in a structured way.
Stay tuned for future articles where we could extend this further, perhaps by integrating a database to manage larger amounts of data or adding more complex business logic.
Top comments (0)