如何将文件路径数组转换为分层JSON结构

我正在尝试在给定其所有文件和路径的数组的情况下创建机器目录结构的JSON。

该数组看起来像这样:

string[] dirArray = { "./proc/15/task/15/exe", "./proc/15/task/15/mounts/mounts.xml", "./proc/15/task/15/mountinfo/mountinfo.xml", "./proc/15/task/15/clear_refs/clear_ref.xml", "./proc/14/loginuid/loginuid.xml", "./proc/14/sessionid/sessionid.xml", "./proc/14/coredump_filter/coredump_filter.xml", "./proc/14/io/io.xml" } 

我瞄准的目标JSON是这样的:

 { ".": { "file": { "name":"fileInRoot.xml" }, "proc": { "file": { "name":"fileInProc.xml" }, "15": { "file": { "name":"fileIn15.xml" }, "task": { "file": { "name":"fileInTask.xml" }, "15": { "file": { "name":"fileInTask.xml" }, "mounts": { "file": { "name":"fileInMounts.xml" } }, "mountsInfo": { "file": { "name":"fileInMountsInfo.xml" } }, "clear_refs": { "file": { "name":"fileInClear_Refs.xml" } } } } }, "14": { "file": { "name":"fileIn14.xml" }, "task": { "file": { "name":"fileInTask.xml" }, "loginUid": { "file": { "name":"fileInloginUid.xml" } }, "sessionid": { "file": { "name":"fileInsessionid.xml" } }, "coreDump_filter": { "file": { "name":"fileIncoreDump_filter.xml" } }, "io": { "file": { "name":"fileInIo.xml" } } } } } } } 

我想创建一个JSON文件,允许JSON的使用者组件浏览此目录结构。 我一直在尝试使用DirectoryFilePath类,但最好的方法是使用java.serializor(?)类来构造JSON,因为我循环遍历数组,解析它的目录和文件,因为我去了?

我想我会把它分成两部分来解决这个问题。 首先,我们需要一种方法来解析目录/文件路径数组并将其放入分层结构中。 其次,我们需要采用该结构并将其转换为JSON。 (我不完全确定你想要使用哪个序列化器的问题,所以对于这个答案我会假设Json.Net没问题 。)

对于第一部分,我将创建一个Dir类,它具有名称,子目录字典(便于查找)和一组文件。 我们可以在这个类中创建一个方法,它将解析路径并找到或添加适当的子对象。

 class Dir { public string Name { get; set; } public Dictionary Dirs { get; set; } public HashSet Files { get; set; } public Dir(string name) { Name = name; Dirs = new Dictionary(); Files = new HashSet(); } public Dir FindOrCreate(string path, bool mightBeFile = true) { int i = path.IndexOf('/'); if (i > -1) { Dir dir = FindOrCreate(path.Substring(0, i), false); return dir.FindOrCreate(path.Substring(i + 1), true); } if (path == "") return this; // if the name is at the end of a path and contains a "." // we assume it is a file (unless it is "." by itself) if (mightBeFile && path != "." && path.Contains(".")) { Files.Add(path); return this; } Dir child; if (Dirs.ContainsKey(path)) { child = Dirs[path]; } else { child = new Dir(path); Dirs.Add(path, child); } return child; } } 

使用这个类,我们可以轻松遍历问题中给出的dirArray并创建目录层次结构:

 Dir root = new Dir(""); foreach (string dir in dirArray) { root.FindOrCreate(dir); } 

所以在这一点上, root现在拥有整个目录层次结构。 如果您愿意,可以直接使用Json.Net序列化此对象以获得合理的JSON结构。 但是,它会比您在问题中描述的更冗长。 这是将生成的JSON:

 { "Name": "", "Dirs": { ".": { "Name": ".", "Dirs": { "proc": { "Name": "proc", "Dirs": { "15": { "Name": "15", "Dirs": { "task": { "Name": "task", "Dirs": { "15": { "Name": "15", "Dirs": { "exe": { "Name": "exe", "Dirs": {}, "Files": [] }, "mounts": { "Name": "mounts", "Dirs": {}, "Files": [ "mounts.xml" ] }, "mountinfo": { "Name": "mountinfo", "Dirs": {}, "Files": [ "mountinfo.xml", "moremountinfo.xml" ] }, "clear_refs": { "Name": "clear_refs", "Dirs": {}, "Files": [ "clear_ref.xml" ] } }, "Files": [] } }, "Files": [] } }, "Files": [] }, "14": { "Name": "14", "Dirs": { "loginuid": { "Name": "loginuid", "Dirs": {}, "Files": [ "loginuid.xml" ] }, "sessionid": { "Name": "sessionid", "Dirs": {}, "Files": [ "sessionid.xml" ] }, "coredump_filter": { "Name": "coredump_filter", "Dirs": {}, "Files": [ "coredump_filter.xml" ] }, "io": { "Name": "io", "Dirs": {}, "Files": [ "io.xml" ] } }, "Files": [] } }, "Files": [] } }, "Files": [] } }, "Files": [] } 

要获得您的目标JSON,我们需要一个JsonConverter类:

 class DirConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(Dir)); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { Dir dir = (Dir)value; JObject obj = new JObject(); if (dir.Files.Count > 0) { JArray files = new JArray(); foreach (string name in dir.Files) { files.Add(new JValue(name)); } obj.Add("list_of_files", files); } foreach (var kvp in dir.Dirs) { obj.Add(kvp.Key, JToken.FromObject(kvp.Value, serializer)); } obj.WriteTo(writer); } public override bool CanRead { get { return false; } } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } } 

我们可以使用转换器序列化目录层次结构,如下所示:

 JsonSerializerSettings settings = new JsonSerializerSettings(); settings.Converters.Add(new DirConverter()); settings.Formatting = Formatting.Indented; string json = JsonConvert.SerializeObject(root, settings); 

这是输出。 请注意,我将原始JSON中的“文件”属性更改为数组,并根据您的注释将其重命名为“list_of_files”以适应每个目录多个文件的可能性。 我还假设永远不会有一个名为“list_of_files”的实际目录。 如果可能,您需要将files数组的名称更改为不会与任何目录名冲突的其他名称。 (如果您遇到错误,上面写着“ Can not add property list_of_files to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object ”,这意味着您的数据中某个目录的名称为“list_of_files” 。)

 { ".": { "proc": { "15": { "task": { "15": { "exe": {}, "mounts": { "list_of_files": [ "mounts.xml" ] }, "mountinfo": { "list_of_files": [ "mountinfo.xml" ] }, "clear_refs": { "list_of_files": [ "clear_ref.xml" ] } } } }, "14": { "loginuid": { "list_of_files": [ "loginuid.xml" ] }, "sessionid": { "list_of_files": [ "sessionid.xml" ] }, "coredump_filter": { "list_of_files": [ "coredump_filter.xml" ] }, "io": { "list_of_files": [ "io.xml" ] } } } } } 

小提琴: https : //dotnetfiddle.net/ConJiu