使用 Node.js 将文件系统中的目录结构转换为 JSON

IT技术 javascript node.js d3.js filesystems
2021-01-24 22:00:57

我有这样的文件结构:

root
|_ fruits
|___ apple
|______images
|________ apple001.jpg
|________ apple002.jpg
|_ animals
|___ cat
|______images
|________ cat001.jpg
|________ cat002.jpg

我想使用 Javascript 和 Node.js,监听这个根目录和所有子目录并创建一个 JSON 来反映这个目录结构,每个节点包含类型、名称、路径和子节点:

data = [
  {
    type: "folder",
    name: "animals",
    path: "/animals",
    children: [
      {
        type: "folder",
        name: "cat",
        path: "/animals/cat",
        children: [
          {
            type: "folder",
            name: "images",
            path: "/animals/cat/images",
            children: [
              {
                type: "file",
                name: "cat001.jpg",
                path: "/animals/cat/images/cat001.jpg"
              }, {
                type: "file",
                name: "cat001.jpg",
                path: "/animals/cat/images/cat002.jpg"
              }
            ]
          }
        ]
      }
    ]
  }
];

这是一个咖啡脚本 JSON:

data = 
[
  type: "folder"
  name: "animals"
  path: "/animals"
  children  :
    [
      type: "folder"
      name: "cat"
      path: "/animals/cat"
      children:
        [
          type: "folder"
          name: "images"
          path: "/animals/cat/images"
          children: 
            [
              type: "file"
              name: "cat001.jpg"
              path: "/animals/cat/images/cat001.jpg"
            , 
              type: "file"
              name: "cat001.jpg"
              path: "/animals/cat/images/cat002.jpg"
            ]
        ]
    ]
]

如何在 Django 视图中获取这种 json 数据格式?(python)

6个回答

这是一个草图。错误处理留给读者作为练习。

var fs = require('fs'),
    path = require('path')

function dirTree(filename) {
    var stats = fs.lstatSync(filename),
        info = {
            path: filename,
            name: path.basename(filename)
        };

    if (stats.isDirectory()) {
        info.type = "folder";
        info.children = fs.readdirSync(filename).map(function(child) {
            return dirTree(filename + '/' + child);
        });
    } else {
        // Assuming it's a file. In real life it could be a symlink or
        // something else!
        info.type = "file";
    }

    return info;
}

if (module.parent == undefined) {
    // node dirTree.js ~/foo/bar
    var util = require('util');
    console.log(util.inspect(dirTree(process.argv[2]), false, null));
}
是的。创建的对象很好,但默认情况下,console.log 仅将对象打印到有限的深度。我编辑了代码以打印完整的树。
2021-03-15 22:00:57
这在第一层效果很好,但是,孩子们看起来像:children: [Object] ...你在这里看到任何问题吗?
2021-03-26 22:00:57
谢谢你的功能。我想最好使用 path.join 而不是a + '/' + b.return dirTree( path.join(filename, child));
2021-04-06 22:00:57
@peterButcher 如果它们以树状结构打印,您会如何订购它们?但是你可以使用 lodash 来构造返回的对象..它只是一个普通对象,所以像其他任何东西一样对其进行排序:)
2021-04-07 22:00:57
如何对输出进行排序,使目录首先出现(按字母顺序),然​​后是文件(也按字母顺序)?
2021-04-09 22:00:57

有一个 NPM module

https://www.npmjs.com/package/directory-tree

创建一个表示目录树的对象。

从:

photos
├── summer
│   └── june
│       └── windsurf.jpg
└── winter
    └── january
        ├── ski.png
        └── snowboard.jpg

到:

{
  "path": "",
  "name": "photos",
  "type": "directory",
  "children": [
    {
      "path": "summer",
      "name": "summer",
      "type": "directory",
      "children": [
        {
          "path": "summer/june",
          "name": "june",
          "type": "directory",
          "children": [
            {
              "path": "summer/june/windsurf.jpg",
              "name": "windsurf.jpg",
              "type": "file"
            }
          ]
        }
      ]
    },
    {
      "path": "winter",
      "name": "winter",
      "type": "directory",
      "children": [
        {
          "path": "winter/january",
          "name": "january",
          "type": "directory",
          "children": [
            {
              "path": "winter/january/ski.png",
              "name": "ski.png",
              "type": "file"
            },
            {
              "path": "winter/january/snowboard.jpg",
              "name": "snowboard.jpg",
              "type": "file"
            }
          ]
        }
      ]
    }
  ]
}

用法

var tree = directoryTree('/some/path');

您还可以按扩展名过滤:

var filteredTree = directoryTree('/some/path', ['.jpg', '.png']);
这正是我所需要的。谢谢。它工作得很好。
2021-04-02 22:00:57

接受的答案有效,但它是同步的,并且会严重损害您的性能,尤其是对于大型目录树。
我强烈建议您使用以下异步解决方案,它既更快又无阻塞。
基于这里的并行解决方案

var fs = require('fs');
var path = require('path');

var diretoryTreeToObj = function(dir, done) {
    var results = [];

    fs.readdir(dir, function(err, list) {
        if (err)
            return done(err);

        var pending = list.length;

        if (!pending)
            return done(null, {name: path.basename(dir), type: 'folder', children: results});

        list.forEach(function(file) {
            file = path.resolve(dir, file);
            fs.stat(file, function(err, stat) {
                if (stat && stat.isDirectory()) {
                    diretoryTreeToObj(file, function(err, res) {
                        results.push({
                            name: path.basename(file),
                            type: 'folder',
                            children: res
                        });
                        if (!--pending)
                            done(null, results);
                    });
                }
                else {
                    results.push({
                        type: 'file',
                        name: path.basename(file)
                    });
                    if (!--pending)
                        done(null, results);
                }
            });
        });
    });
};

用法示例:

var dirTree = ('/path/to/dir');

diretoryTreeToObj(dirTree, function(err, res){
    if(err)
        console.error(err);

    console.log(JSON.stringify(res));
});
小问题:你在 diretoryTreeToObj 中有一个错字,我认为它应该是 directoryTreeToObj 不是吗?
2021-03-19 22:00:57

我的 CS 示例(带快递)基于 Miika 的解决方案:

fs = require 'fs' #file system module
path = require 'path' # file path module

# returns json tree of directory structure
tree = (root) ->
    # clean trailing '/'(s)
    root = root.replace /\/+$/ , ""
    # extract tree ring if root exists
    if fs.existsSync root
        ring = fs.lstatSync root
    else
        return 'error: root does not exist'
    # type agnostic info
    info = 
        path: root
        name: path.basename(root)
    # dir   
    if ring.isDirectory()
        info.type = 'folder'
        # execute for each child and call tree recursively
        info.children = fs.readdirSync(root) .map (child) ->
            tree root + '/' + child
    # file
    else if ring.isFile()
        info.type = 'file'
    # link
    else if ring.isSymbolicLink()
        info.type = 'link'
    # other
    else
        info.type = 'unknown'
    # return tree 
    info

# error handling
handle = (e) ->
    return 'uncaught exception...'

exports.index = (req, res) ->
    try
        res.send tree './test/'
    catch e
        res.send handle e

您可以使用此项目中的代码,但您应该根据自己的需要调整代码:

https://github.com/NHQ/Node-FileUtils/blob/master/src/file-utils.js#L511-L593

从:

a
|- b
|  |- c
|  |  |- c1.txt
|  |
|  |- b1.txt
|  |- b2.txt
|
|- d
|  |
|
|- a1.txt
|- a2.txt

到:

{
    b: {
        "b1.txt": "a/b/b1.txt",
        "b2.txt": "a/b/b2.txt",
        c: {
            "c1.txt": "a/b/c/c1.txt"
        }
    },
    d: {},
    "a2.txt": "a/a2.txt",
    "a1.txt": "a/a1.txt"
}

正在做:

new File ("a").list (function (error, files){
    //files...
});
我从github中删除了该项目。这个链接是一个分叉。
2021-03-24 22:00:57
@GabrielLlamas 为什么将其从 github 中删除?对我来说似乎是一个相当有用的项目。
2021-03-29 22:00:57