Peter Girnus

View Original

Rust std::fs: Parsing Directories & File Entries with DirEntry

Introduction

The Rust programming language provides a robust and efficient way to interact with the file system, making it a popular choice for systems programming and file manipulation tasks. In this mini how-to guide, we will explore the powerful capabilities of the DirEntry struct, which is part of the Rust standard library's std::fs module. DirEntry enables developers to navigate and extract valuable information from directory entries effortlessly, making it an essential tool for file-related operations.

Understanding DirEntry in Rust

Let’s first understand what a rust DirEntry object is before we approach using this struct in a practical problem.

What is DirEntry

DirEntry is a struct that plays a pivotal role in Rust's file system handling. It is returned by the ReadDir iterator, allowing you to access and manipulate properties of individual directory entries with ease. With DirEntry, you can effortlessly gather a wealth of information about files and directories, including their path, metadata, file type, and more.

Extracting DirEntry Information

When working with DirEntry, you can extract an array of essential attributes from directory entries. Some of the key information you can obtain include:

  • Path: Discover the full path to the directory entry.

  • Metadata: Access detailed file metadata, including permissions, whether it's a directory or a file, creation, modification, and access times, file type, and Unix mode.

  • OS String: Retrieve an OS-specific string representation of the directory entry.

  • Filename: Obtain the name of the directory entry.

  • Filetype: Determine the type of file or directory entry using various methods, including the Metadata struct.

Problem Definition

Before diving into the details of how to interact with DirEntry in Rust, it's crucial to define a practical problem that we'll address throughout this guide. Let's set the stage by defining our problem:

Problem: Imagine you are building a file management tool in Rust. You need to create a feature that lists all the files and directories within a specified directory, displaying their names, sizes, and last modification dates. Additionally, you want to identify and mark directories with a special symbol in the list. How can you achieve this efficiently using Rust's DirEntry?

In the following sections, we will break down this problem step by step, demonstrating how to use DirEntry to solve it effectively. By the end of this mini how-to, you'll have a clear understanding of how to harness the power of Rust's DirEntry to manage and extract valuable information from directory entries in your projects. Let's get started!

Solution

Let’s solve our practical problem with the following steps:

Import Required Libraries

To begin we need to import the std::fs module using the following declaration.

See this content in the original post

Optionally we can import DirEntryExt2 inside our main.rs file which imports Unix-specific extension methods. This is an experimental implementation available for nightly Rust.

See this content in the original post

Creating a Rust Module: dir_entry_mod

In this example I will leverage Rust’s powerful module system to create a mod that handles the collection of DirEntry objects. This will allow me to write clean and modular code, allowing me to keep my main.rs file reserved for business logic.

Inside of the main projects src directory I have a mods/ directory which contains a series of mods.

Example mod directory structure

Inside of the mods/ directory create the file mod.rs, the full path should be src/mods/mod.rs. In this mod file we will add a pub mod entry for our dir_entry_mod. Using the pub keyword allows this module to be accessible to external modules.

See this content in the original post

If further nesting occurs, such as each mod having it’s own directory we need to also create a mod.rs in that directory as well such as src/mods/dire_entry_mod/mod.rs in order to make the nested module accessible.

I will define a pub mod of direntries since I will write my function to collect DirEntry objects inside of dir_entries.rs.

See this content in the original post

Once we have linked the mods and made them accessible externally using the pub keyword we can call the main mods directory inside our main.rs file under our imports.

See this content in the original post

Defining Our Mod Function: get_dir_entries()

Once we have our mod structure in place we can proceed to write the get_dir_entries() function that collects DirEntry. We can define this function inside of src/mods/dir_entry_mod/dir_entries.rs which will take a string reference to a directory we want to collect from. This directory will be read using the read_dir() method. Finally our function will return a vector of DirEntry structs. Each DirEntry will correspond to a unique entry encountered inside the directory we passed as an argument to our function.

See this content in the original post

Creating the Vector to Store Our DirEntry Structs

Inside of our rust function we need to define a variable that will hold our DirEntry values. We will define this variable with the help of the vec! macro.

See this content in the original post

Next we need to call the read_dir() method to read the path we passed to our function as an argument. For each DirEntry we need to push that object to dir_entries vector.

See this content in the original post

Once we have collected all DirEntry objects we can return our vec.

See this content in the original post

Interacting with DirEntry Objects

Once we have the function created to gather our DirEntry objects we can access various DirEntry methods in order to find out information about this specific DirEntry such as path, metadata, OS string, filename, and file type.

Inside of our main function inside of main.rs we can set a variable that contains a reference to a path we want to collect DirEntry objects from.

See this content in the original post

Next we can pass this variable to our function and store the result inside of a variable.

See this content in the original post

Next we can use rust’s pattern matching capabilities with the match keyword which gives the engineer access to flow control.

See this content in the original post

Inside our flow control statement we can iterate over our DirEntry object vector using a for loop.

See this content in the original post

Inside of our loop can iterate over each DirEntry and access information such as ile name, path, metadata, and file type.

Getting the DirEntry File Name

We can use the file_name() method on the DirEntry object to access the DirEntry object filename.

See this content in the original post

Getting the DirEntry Path

We can use the path() method on the DirEntry object to gain access to the DirEntry object path.

See this content in the original post

Getting the DirEntry Metadata

We can use the metadata() method on the DirEntry object to gain access to the DirEntry object metadata methods.

See this content in the original post

Once we have stored the DirEntry’s Metadata object we can access the following:

Getting the DirEntry Permissions

We can access the DirEntry permissions with the permissions() method.

See this content in the original post

Check if DirEntry is a Directory

We can check to see if the DirEntry is a directory with the is_dir() method.

See this content in the original post

Check if DirEntry is a Symbolic Link (Symlink)

We can check to see if the DirEntry is a symlink with the is_symlink() method.

See this content in the original post

Check if DirEntry is a File

We can check to see if the DirEntry is a file with the is_file() method.

See this content in the original post

Getting the DirEntry Filetype from Metadata

We can get the DirEntry filetype directly from our Metadata object using the file_type() method.

See this content in the original post

Getting the DirEntry Mode (IF Unix)

If we are working with Unix DirEntry objects we can access the unix mode by firsting importing MetadataExt. After which we can call the mode() method.

See this content in the original post

Getting the DirEntry Byte Size

We can get the size of the DirEntry in bytes using the len() method.

See this content in the original post

Getting the DirEntry Created Time

We can get the DirEntry created time using the created() method.

See this content in the original post

Getting the DirEntry Modified Time

We can get the DirEntry modified time using the modified() method.

See this content in the original post

Getting the DirEntry Accessed Time

We can get the DirEntry accessed time using the accessed() method.

See this content in the original post

Getting the DireEntry File Type

Another method to determine the filetype of the DirEntry object is to use the file_type() method directly on the DirEntry itself.

See this content in the original post

Putting Our Solution Together

Below is a complete code example from our code solution, you can also find this project on GitHub.

See this content in the original post

Conclusion

In conclusion, this mini how-to has provided a concise yet comprehensive guide on how to effectively interact with directory entries in Rust using the DirEntry struct from the standard library. By demonstrating how to access and utilize various attributes and methods associated with DirEntry, such as path, metadata, and file type, we have equipped you with the knowledge and tools to navigate and manipulate directory contents in your Rust applications.

By presenting a clear problem-solving approach, this guide has empowered you to tackle real-world scenarios involving directory manipulation with confidence. As you continue to explore the Rust programming language and its libraries, this newfound understanding of DirEntry and directory interactions will undoubtedly prove invaluable in your coding endeavors.

See this social icon list in the original post

If you have any questions feel free to email me or reach out to me on social media. Until next time!