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

时间:2014-10-28 18:10:17

标签: c# json directory

我正在尝试创建一个机器目录结构的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,因为我循环遍历数组,我去的时候解析它的目录和文件?

1 个答案:

答案 0 :(得分:8)

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

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

class Dir
{
    public string Name { get; set; }
    public Dictionary<string, Dir> Dirs { get; set; }
    public HashSet<string> Files { get; set; }

    public Dir(string name)
    {
        Name = name;
        Dirs = new Dictionary<string, Dir>();
        Files = new HashSet<string>();
    }

    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);

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

{
  ".": {
    "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