我目前正在开发一个初学者的项目来实现我自己的重复文件查找器。这是我第一次使用.NET语言,所以我仍然非常不熟悉.NET API。
这是我到目前为止编写的代码:
open System
open System.IO
open System.Collections.Generic
let directory = @somePath
let getAllFiles (directory : string) =
Directory.GetFiles(directory)
let getFileInfo (directory : string) =
directory
|> getAllFiles
|> Seq.map (fun eachFile -> (eachFile, new FileInfo(eachFile)))
let getFileLengths (directory: string) =
directory
|> getFileInfo
|> Seq.map (fun (eachFile, eachFileInfo : FileInfo) -> (eachFile, eachFileInfo.Length))
// If two files have the same lengths, they might be duplicates of each other.
let groupByFileLengths (directory: string) =
directory
|> getFileLengths
|> Seq.groupBy snd
|> Seq.map (fun (fileLength, files) -> fileLength, files |> Seq.map fst |> List.ofSeq)
let findGroupsOfTwoOrMore (directory: string) =
directory
|> groupByFileLengths
|> Seq.filter (snd >> List.length >> (<>) 1)
let constructHashtable (someTuple) =
let hashtable = new Hashtable()
someTuple
|> Seq.iter hashtable.Add
hashtable
let readAllBytes (tupleOfFileLengthsAndFiles) =
tupleOfFileLengthsAndFiles
|> snd
|> Seq.map (fun eachFile -> (File.ReadAllBytes eachFile, eachFile))
|> constructHashtable
我想要做的是构造一个哈希表,每个文件的字节数组作为键,文件名本身作为值。如果具有不同文件名的多个文件共享相同的bye数组,则它们是重复的,我的目标是删除重复的文件。
我查看了MSDN上的Hashtable命名空间,但是没有方法可以识别包含多个值的哈希表键。
编辑:这是我尝试实施MD5:
let readAllBytesMD5 (tupleOfFileLengthsAndFiles) =
let md5 = MD5.Create()
tupleOfFileLengthsAndFiles
|> snd
|> Seq.map (fun eachFile -> (File.ReadAllBytes eachFile, eachFile))
|> Seq.map (fun (byteArray, eachFile) -> (md5.ComputeHash(byteArray), eachFile))
|> Seq.map (fun (hashCode, eachFile) -> (hashCode.ToString, eachFile))
请告知我如何改进和继续,因为我没有牢牢掌握MD5的工作原因而被困在这里。谢谢。
答案 0 :(得分:2)
Hashtable
不支持同一个键的多个值 - 当您尝试使用相同的键添加第二个条目时,您将收到异常。它也是无类型的,您几乎总是喜欢键入的可变System.Collections.Generic.Dictionary
或不可变的F#Map
。
您要找的是Map<byte array, Set<string>>
。这是我的看法:
let buildMap (paths: string array) =
paths
|> Seq.map (fun eachFile -> (File.ReadAllBytes eachFile, eachFile))
|> Seq.groupBy fst
|> Seq.map (fun (key, items) ->
key, items |> Seq.map snd |> Set.ofSeq)
|> Map.ofSeq
顺便说一句,除非你要比较非常非常小的文件,否则使用整个文件内容作为密钥不会让你走得太远。您可能希望研究为这些文件生成校验和并使用它们。