La conversione di una struttura di directory nel filesystem JSON con Node.js

Ho una struttura di file come questo:

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

Vorrei, utilizzo di Javascript e Node.js sentite questa directory principale e tutte le sottocartelle e creare un file JSON, che è specchio di questa struttura di directory, ogni nodo contiene il tipo, il nome, il percorso e bambini:

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"
              }
            ]
          }
        ]
      }
    ]
  }
];

Ecco un coffeescript 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"
            ]
        ]
    ]
]

come ottenere questo json formato dei dati in django vista?(python)

  • Questo è un requisito comune nell’acquisizione di d3.js dati gerarchici. Mi piacerebbe tag a questa domanda con d3.js ma Overflow dello Stack consente un massimo di 5 🙁
  • Vorrei una di queste risposte sarebbe leggere i percorsi da stdin, in modo che è possibile convertire un elenco di percorsi in un oggetto json, come questo: find | paths2json. In grado di sfruttare a pieno la potenza di Unix componibilità attraverso le tubazioni.
InformationsquelleAutor hagope | 2012-06-25

 

8 Replies
  1. 67

    Ecco uno schizzo. La gestione degli errori è lasciato come esercizio per il lettore.

    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));
    }
    • Questo funziona alla grande il 1 ° livello, tuttavia, i bambini guardano come: bambini: [Oggetto] … non si vede alcun problema?
    • Sì, sì, sì. L’oggetto creato è bene, ma da console di default.registro stampe di oggetti solo per una limitata profondità. Ho modificato il codice per stampare l’albero completo.
    • Funziona alla grande, grazie!
    • Grazie per il func. Credo che un uso migliore percorso.unire invece di a + '/' + b. return dirTree( path.join(filename, child));
    • Come fare per ordinare la produzione, in modo che le directory appaiono prima (in ordine alfabetico) seguita da file (anche in ordine alfabetico)?
    • Ho appena trovato questo, funziona alla grande
    • Come ordinare se il suo stampata in una struttura ad albero? Ma è possibile utilizzare lodash alla struttura l’oggetto restituito.. è solo un normale oggetto, in modo da ordinare come si farebbe con qualsiasi altra cosa 🙂
    • Ho avuto la mia risposta qui: stackoverflow.com/questions/31699673/…

  2. 21

    c’è un NPM Modulo

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

    Crea un oggetto che rappresenta un albero di directory.

    Da:

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

    A:

    {
      "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"
                }
              ]
            }
          ]
        }
      ]
    }

    Utilizzo

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

    E puoi anche filtrare dalle estensioni:

    var filteredTree = directoryTree('/some/path', ['.jpg', '.png']);
    • Questo era esattamente quello che mi serviva. Grazie. Funziona alla grande.
    • Stesso. Grande modulo, ha funzionato perfettamente.
  3. 18

    Accettato di rispondere lavori, ma è sincrono e profondamente ferito vostre prestazioni, in particolare per i grandi alberi di directory.

    I altamente consigliamo di utilizzare il seguente asincrona soluzione, è più veloce e non di blocco.

    Basato sul parallelo soluzione qui.

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

    Esempio di utilizzo:

    var dirTree = ('/path/to/dir');
    
    diretoryTreeToObj(dirTree, function(err, res){
        if(err)
            console.error(err);
    
        console.log(JSON.stringify(res));
    });
    • minori nit: si dispone di un errore di battitura nel diretoryTreeToObj, penso che dovrebbe essere directoryTreeToObj no?
  4. 3

    Mio CS esempio (w/express) basato su Miika soluzione:

    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
  5. 1

    È possibile utilizzare il codice di questo progetto, ma si dovrebbe adattare il codice alle tue esigenze:

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

    Da:

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

    A:

    {
        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"
    }

    Fare:

    new File ("a").list (function (error, files){
        //files...
    });
    • Il link sembra di avere cambiato in: github.com/NHQ/Node-FileUtils
    • Ho rimosso il progetto da github. Questo link è stato una forchetta.
    • Perché questo è stato rimosso da github? Sembra piuttosto un progetto utile per me.
  6. 1

    Qui è un async soluzione:

     function list(dir) {
       const walk = entry => {
         return new Promise((resolve, reject) => {
           fs.exists(entry, exists => {
             if (!exists) {
               return resolve({});
             }
             return resolve(new Promise((resolve, reject) => {
               fs.lstat(entry, (err, stats) => {
                 if (err) {
                   return reject(err);
                 }
                 if (!stats.isDirectory()) {
                   return resolve({
                     //path: entry,
                     //type: 'file',
                     name: path.basename(entry),
                     time: stats.mtime,
                     size: stats.size
                   });
                 }
                 resolve(new Promise((resolve, reject) => {
                   fs.readdir(entry, (err, files) => {
                     if (err) {
                       return reject(err);
                     }
                     Promise.all(files.map(child => walk(path.join(entry, child)))).then(children => {
                       resolve({
                         //path: entry,
                         //type: 'folder',
                         name: path.basename(entry),
                         time: stats.mtime,
                         entries: children
                       });
                     }).catch(err => {
                       reject(err);
                     });
                   });
                 }));
               });
             }));
           });
         });
       }
    
       return walk(dir);
     }

    Notare che quando una directory non esiste il vuoto viene restituito il risultato piuttosto che un errore generata.

    Qui è un esempio di risultato:

    {
        "name": "root",
        "time": "2017-05-09T07:46:26.740Z",
        "entries": [
            {
                "name": "book.txt",
                "time": "2017-05-09T07:24:18.673Z",
                "size": 0
            },
            {
                "name": "cheatsheet-a5.pdf",
                "time": "2017-05-09T07:24:18.674Z",
                "size": 262380
            },
            {
                "name": "docs",
                "time": "2017-05-09T07:47:39.507Z",
                "entries": [
                    {
                        "name": "README.md",
                        "time": "2017-05-08T10:02:09.651Z",
                        "size": 19229
                    }
                ]
            }
        ]
    }

    che sarà:

    root
    |__ book.txt
    |__ cheatsheet-a5.pdf
    |__ docs
          |__ README.md
  7. 0

    Ho usato ‘a piedi’ lib in questo caso, si ottiene il vostro percorso principale e passeggiate su file e su di directory in modo ricorsivo ed emette un evento di directory /file con tutte le info di cui avete bisogno da un nodo,
    controllare che l’attuazione –>

    const walk = require('walk');
    
    class FsTree {
    
        constructor(){
    
        }
    
        /**
         * @param rootPath
         * @returns {Promise}
         */
        getFileSysTree(rootPath){
            return new Promise((resolve, reject)=>{
    
                const root = rootPath || __dirname; //if there's no rootPath use exec location
                const tree = [];
                const nodesMap = {};
                const walker  = walk.walk(root, { followLinks: false}); //filter doesn't work well
    
                function addNode(node, path){
                    if ( node.name.indexOf('.') === 0 || path.indexOf('/.') >= 0){ //ignore hidden files
                        return;
                    }
                    var relativePath = path.replace(root,'');
    
                    node.path = relativePath + '/' + node.name;
                    nodesMap[node.path] = node;
    
                    if ( relativePath.length === 0 ){ //is root
                        tree.push(node);
                        return;
                    }
                    node.parentPath = node.path.substring(0,node.path.lastIndexOf('/'));
                    const parent = nodesMap[node.parentPath];
                    parent.children.push(node);
    
                }
    
                walker.on('directory', (path, stats, next)=>{
                    addNode({ name: stats.name, type:'dir',children:[]}, path);
                    next();
                });
    
                walker.on('file', (path,stats,next)=>{
                    addNode({name:stats.name, type:'file'},path);
                    next();
                });
    
                walker.on('end',()=>{
                    resolve(tree);
                });
    
                walker.on('errors',  (root, nodeStatsArray, next) => {
                    reject(nodeStatsArray);
                    next();
                });
            });
    
        }
    }
    
    
    const fsTreeFetcher = new FsTree();
    
    fsTreeFetcher.getFileSysTree(__dirname).then((result)=>{
        console.log(result);
    });
  8. 0

    Questo è il miglior modulo per attività di:

    npm dree

    Ci sono un sacco di opzioni di personalizzazione, un risultato potrebbe essere questo:

    {
      "name": "sample",
      "path": "D:/Github/dree/test/sample",
      "relativePath": ".",
      "type": "directory",
      "size": "1.79 MB",
      "children": [
        {
          "name": "backend",
          "path": "D:/Github/dree/test/sample/backend",
          "relativePath": "backend",
          "type": "directory",
          "size": "1.79 MB",
          "children": [
            {
              "name": "firebase.json",
              "path": "D:/Github/dree/test/sample/backend/firebase.json",
              "relativePath": "backend/firebase.json",
              "type": "file",
              "extension": "json",
              "size": "29 B"
            }, 
            {
              "name": "server",
              "path": "D:/Github/dree/test/sample/backend/server",
              "relativePath": "backend/server",
              "type": "directory",
              "size": "1.79 MB",
              "children": [
                {
                  "name": "server.ts",
                  "path": "D:/Github/dree/test/sample/backend/server/server.ts",
                  "relativePath": "backend/server/server.ts",
                  "type": "file",
                  "extension": "ts",
                  "size": "1.79 MB"
                }
              ]
            }
          ]
        }
      ]
    }

    Anche una stringa potrebbe essere restituito, come questo:

    sample
     └─> backend
         ├── firebase.json
         ├── hello.txt
         └─> server
             └── server.ts

    Esempio:

    const dree = require('dree');
    
    const options = {
      stat: false,
      normalize: true,
      followLinks: true,
      size: true,
      depth: 5,
      exclude: [/dir_to_exclude/, /another_dir_to_exclude/ ],
      extensions: [ 'txt', 'jpg' ]
    };
    
    const tree = dree.scan('./folder', options);

Lascia un commento