使用Fsharp構建文件結構

利用fsharp構建文件結構。

open System.IO
type FileUnit = 
    | Empty 
    | File of string * FileAttributes
    | Directory of string * FileAttributes * FileUnit
    | FDList of seq<FileUnit>
    | FileUnit of FileUnit*FileUnit

let rec getFiles4 path =
    match DirectoryInfo(path).Exists with
    | false -> Empty
    | _     -> match DirectoryInfo(path).Attributes &&& FileAttributes.Directory with
               | FileAttributes.Directory -> let dlst = match Directory.GetDirectories(path).Length with
                                                        |0 -> Empty
                                                        |1 -> Directory(path, DirectoryInfo(path).Attributes, Directory.GetDirectories(path).[0] |> getFiles4)
                                                        |_ -> FDList(seq{
                                                                         for elem in Directory.GetDirectories(path) do               
                                                                             yield Directory(elem, DirectoryInfo(elem).Attributes, getFiles4 elem)})
                                             let flst = match Directory.GetFiles(path).Length with
                                                        |0 -> Empty
                                                        |1 -> File(path, DirectoryInfo(path).Attributes)
                                                        |_ -> FDList(seq{
                                                                        for elem in Directory.GetFiles(path) do
                                                                            yield File(elem, DirectoryInfo(elem).Attributes)})
                                             FileUnit(flst, dlst)
               | _ -> FileUnit(File(path, DirectoryInfo(path).Attributes), Empty )
文件系統是由文件和文件夾組成的。上面的可區分聯合引入了幾個額外的抽象,對象列表,文件及文件夾組合。回頭再來看,解決方案把問題想複雜了。

文件系統最大的特點便是其遞歸的定義,文件夾含文件和文件夾,可區分聯合在這裏描述概念再合適不過了。

新的版本

open System
open System.IO
open System.Threading
open System.Threading.Tasks
open System.Diagnostics

#if INTERACTIVE
#time
#endif

type FileUnit = 
    | FileElem of string * DirectoryInfo
    | DirectoryElem of string * DirectoryInfo * seq<FileUnit>

let rec getFiles path = 
    match Directory.Exists(path),File.Exists(path) with
    |false, true -> FileElem(path, DirectoryInfo(path))
    |true, false -> DirectoryElem(path, DirectoryInfo(path), 
                        Directory.GetFiles(path) |> Seq.collect (fun it -> [FileElem(it, DirectoryInfo(it))])
                        |> Seq.append <| 
                        (Directory.GetDirectories(path) |> Seq.collect (fun it -> [ it |> getFiles ])))
    |_           -> failwith("can not get file or directory")
                            
let rec getFileList fu (ignoreset:Set<string>)= 
    seq{
        match fu with
        |FileElem(name, info) -> yield name, info
        |DirectoryElem(name, info, lst) -> 
            if not (ignoreset.Contains(info.Name)) then
                yield name, info; yield! (lst |> Seq.collect  (fun x -> getFileList x ignoreset))
    }
新版本中文件單元只存在兩種情況,文件和文件夾。在進行模式匹配的時候需要做的事也會少一些。getFileList將樹形的文件結構鋪展爲一個1維列表。由於生成列表的過程中使用了Seq對象,所以執行這兩個函數幾乎是不需要花費時間的,如果有優化也應該在這個時候進行。我在這裏過濾了一些需要忽略的文件列表。

原本的想法還是有些亂,改進的空間總是存在的,此爲止。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章