Table of Contents

This is the second post related to I/O in F# 

 

Directory

The Directory class offers similar functionality to the File class. It has Create and Delete methods, as well as helpers to enumerate the directories.

open System.IO


let path = Path.Combine(".", "my-dir")
let dirinfo = Directory.CreateDirectory(path)
printfn $"%s{dirinfo.Name} - %s{dirinfo.FullName}"
// my-dir - C:\Users\scyth\repos\blogpostdrafts\my-dir 
// To Delete the directory
// use either dirinfo.Delete
// dirinfo.Delete()
// or Directory.Delete
Directory.Delete(dirinfo.FullName)
  


If you try to delete a directory that is not empty, you will get an exception. You can just pass a Boolean to recursively delete everything within that directory.


Directory.Delete(dirinfo.FullName, true)
// or
dirinfo.Delete(true)


That is pretty nice, and if you pay attention to the IDE hints, you'll see that CreateDirectory returns a DirectoryInfo instance which is another class that also has more less the same methods that Directory has. The motivation is that DirectoryInfo operates on a specific directory, instead of a general-purpose class for directories.

What if we want to get the files and directories on the current path?






open System.IO 

let files =
  Directory.EnumerateFiles(".")
  |> Seq.fold (fun prev next -> $"{prev}\n\t{next}") ""
  
    
  let directories =
  	Directory.EnumerateDirectories(".")
 	|> Seq.fold (fun prev next -> $"{prev}\n\t{next}") ""
    
  	printfn $"files:\t{files}\n directories:\t{directories}"
    


The output would be something like:


  files:
  
  .\README.md
  .\sample.log
  .\simple-things-in-fsharp-1.md
  

 

directories:
.\.git .\.ionide .\samples .\scripts


You can create a DirectoryInfo instance yourself:


open System.IO 
  
let dir = DirectoryInfo(".")
let dirs = dir.EnumerateDirectories()
let files = dir.EnumerateFiles()
printfn "directories: %s\nfiles: %s" (dirs.GetType().ToString()) (files.GetType().ToString())
  
// directories: System.IO.Enumeration.FileSystemEnumerable`1[System.IO.DirectoryInfo]
// files: System.IO.Enumeration.FileSystemEnumerable`1[System.IO.FileInfo]


If you want to recursively travel through all the sub-directories within a directory, you can use SearchOption.AllDirectories which will get us a flat list of directories in the specified path.


open System.IO 

let dir = DirectoryInfo(".")
let directories = dir.GetDirectories("*.*", SearchOption.AllDirectories)
printfn "%A" directories
(*
[|C:\Users\scyth\repos\blogpostdrafts\.git;
C:\Users\scyth\repos\blogpostdrafts\.ionide;
C:\Users\scyth\repos\blogpostdrafts\samples;
C:\Users\scyth\repos\blogpostdrafts\scripts;
C:\Users\scyth\repos\blogpostdrafts\.git\hooks;
C:\Users\scyth\repos\blogpostdrafts\.git\info;
C:\Users\scyth\repos\blogpostdrafts\.git\logs;
C:\Users\scyth\repos\blogpostdrafts\.git\objects;
C:\Users\scyth\repos\blogpostdrafts\.git\refs;
C:\Users\scyth\repos\blogpostdrafts\samples\samples2;
C:\Users\scyth\repos\blogpostdrafts\.git\logs\refs;
C:\Users\scyth\repos\blogpostdrafts\.git\objects\info;
C:\Users\scyth\repos\blogpostdrafts\.git\objects\pack;
C:\Users\scyth\repos\blogpostdrafts\.git\refs\heads;
C:\Users\scyth\repos\blogpostdrafts\.git\refs\remotes;
C:\Users\scyth\repos\blogpostdrafts\.git\refs\tags;
C:\Users\scyth\repos\blogpostdrafts\samples\samples2\samples3;
C:\Users\scyth\repos\blogpostdrafts\.git\logs\refs\heads;
C:\Users\scyth\repos\blogpostdrafts\.git\logs\refs\remotes;
C:\Users\scyth\repos\blogpostdrafts\.git\refs\remotes\origin;
C:\Users\scyth\repos\blogpostdrafts\samples\samples2\samples3\samples4;
C:\Users\scyth\repos\blogpostdrafts\.git\logs\refs\remotes\origin|]
*)


This is the output in this specific case. You can play with the pattern to filter out unwanted directories.
Let's now do a relatively common exercise and create a tree like structure of the directory layout.
NOTE: Please keep in mind that this might not be the best way to implement this and is not the best solution. It's just one way to implement.


open System.IO 

// first let's define our data type that will
type Hierarchy =
{ Name: string
Files: string list
Directories: Hierarchy list } 

let getFiles (dir: DirectoryInfo) =
dir.EnumerateFiles()
|> Seq.map (fun file -> file.FullName)
|> List.ofSeq

let getDirectories (dir: DirectoryInfo) = 
dir.EnumerateDirectories() 
|> Seq.filter (fun dir -> not (dir.Name.StartsWith("."))) 
|> List.ofSeq 
  
/// we'll define a recursive function that will take a `List<DirectoryInfo>`
/// and returns a `List<Hierarchy>`
let rec getDirHierarchy (directories: DirectoryInfo list) =
directories
|> List.map
(fun dir ->
{ Name = dir.FullName
Files = getFiles dir
Directories = getDirHierarchy (getDirectories dir) }) 
  
let getHierarchy (path: string) =
let dir = DirectoryInfo(path)
{ Name = dir.FullName
Files = getFiles dir
Directories = getDirHierarchy (getDirectories dir) } 
  
let hierarchy = getHierarchy "."
printfn $"%A{hierarchy}"
(*
  { Name = "C:\Users\scyth\repos\blogpostdrafts"
  Files =
  [C:\Users\scyth\repos\blogpostdrafts\README.md;
  C:\Users\scyth\repos\blogpostdrafts\sample.log;
  C:\Users\scyth\repos\blogpostdrafts\simple-things-in-fsharp-1.md;
  C:\Users\scyth\repos\blogpostdrafts\simple-things-in-fsharp-2.md]
  Directories =
  [{ Name = "C:\Users\scyth\repos\blogpostdrafts\samples"
  Files = [C:\Users\scyth\repos\blogpostdrafts\samples\moved.txt]
  Directories =
  [{ Name = "C:\Users\scyth\repos\blogpostdrafts\samples\samples2"
  Files =
  [C:\Users\scyth\repos\blogpostdrafts\samples\samples2\moved2.txt]
  Directories =
  [{ Name =
  "C:\Users\scyth\repos\blogpostdrafts\samples\samples2\samples3"
  Files = []
  Directories =
  [{ Name =
  "C:\Users\scyth\repos\blogpostdrafts\samples\samples2\samples3\samples4"
  Files = []
  Directories = [] }] }] }] };
  { Name = "C:\Users\scyth\repos\blogpostdrafts\scripts"
  Files =
  [C:\Users\scyth\repos\blogpostdrafts\scripts\http.fsx;
  C:\Users\scyth\repos\blogpostdrafts\scripts\stif-1-2.fsx;
  C:\Users\scyth\repos\blogpostdrafts\scripts\stif-1-3.fsx;
  C:\Users\scyth\repos\blogpostdrafts\scripts\stif-1-4.fsx;
  C:\Users\scyth\repos\blogpostdrafts\scripts\stif-1-5.fsx;
  C:\Users\scyth\repos\blogpostdrafts\scripts\stif-1-6.fsx;
  C:\Users\scyth\repos\blogpostdrafts\scripts\stif-1-7.fsx;
  C:\Users\scyth\repos\blogpostdrafts\scripts\stif-1-8.fsx;
  C:\Users\scyth\repos\blogpostdrafts\scripts\stif-1.fsx]
  Directories = [] }] }
*)


To move a directory and all of its contents, simply use the DirectoryInfo.MoveTo or Directory.Move but please keep in mind that MoveTo is a method of DirectoryInfo instance


open System.IO
  
Directory.Move("./samples", "./samples2")
  
// check the directory was moved before running the last bits
  
let dir = DirectoryInfo("./samples2")
// move it back to it's original place
dir.MoveTo("./samples")
So, that's it! We can now close the IO chapter. These are common operations of the IO namespace. Remember that your code runs in .NET, so don't feel afraid to use existing libraries from other languages such as C# and VB.

About Encora

Fast-growing tech companies partner with Encora to outsource product development and drive growth. Contact us to learn more about our software engineering capabilities.

Contact Us

Learn More about Encora

We are the software development company fiercely committed and uniquely equipped to enable companies to do what they can’t do now.

Learn More

Global Delivery

READ MORE

Careers

READ MORE

Industries

READ MORE

Related Insights

Enabling Transformation in Hospitality through Technology-Led Innovation

As the exclusive sponsor of the 2024 Hotel Visionary Awards, we support organizations leading ...

Read More

Key Insights from HLTH 2024: The Future of Patient-Centered Healthcare

Discover key insights from HLTH 2024 on digital health, AI in diagnostics, data interoperability, ...

Read More

Data-Driven Engineering: Transforming Operations and Products from Insight to Impact

Discover how data-driven engineering transforms operations and product development, enhancing team ...

Read More
Previous Previous
Next

Accelerate Your Path
to Market Leadership 

Encora logo

Santa Clara, CA

+1 669-236-2674

letstalk@encora.com

Innovation Acceleration

Speak With an Expert

Encora logo

Santa Clara, CA

+1 (480) 991 3635

letstalk@encora.com

Innovation Acceleration