DEV Community

mohamed Tayel
mohamed Tayel

Posted on

Mastering C# Fundamentals: Book Management Application File Handling for Saving and Loading Data

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";
Enter fullscreen mode Exit fullscreen mode

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.");
}
Enter fullscreen mode Exit fullscreen mode

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.");
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 our CheckForExistingBookFile() ensures the directory is created if it does not already exist.

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)