将文件路径数组拆分为JavaScript中的分层对象

时间:2017-04-15 22:18:57

标签: javascript jszip

使用JSZip解压缩文件时会给出一个文件夹和文件列表。例如,当我运行

files.forEach((relativePath, file) => {
  console.log(relativePath);
});

我明白了:

three-dxf-master/
three-dxf-master/.DS_Store
three-dxf-master/.gitignore
three-dxf-master/LICENSE
three-dxf-master/README.md
three-dxf-master/bower.json
three-dxf-master/bower_components/

其中一些是目录,一些是文件。 我可以通过检查file.dir来判断哪些是目录。 我想将其拆分为分层数据结构。我想把它分开:

{
  "three-dxf-master": [
    ".DS_Store",
    ".gitignore",
    "LICENSE",
    "README.md",
    "bower.json",
    {
      "bower_components": [
        ".DS_Store",
        {
          "dxf-parser": [...]
        }
      ]
    }
  ]
}

这样我就可以将它发送到Vue并在一个漂亮的文件查看器中进行格式化。我查看了文档,但我没有看到为文件创建层次结构数据结构的简单方法。我开始通过在分割后抓取文件路径中的最后一个来研究这个问题。

3 个答案:

答案 0 :(得分:4)

这是一个示例代码,它也处理root文件。

请参阅以下代码摘要解释

var paths = [
    "three-dxf-master/",
    "three-dxf-master/.DS_Store",
    "three-dxf-master/.gitignore",
    "three-dxf-master/LICENSE",
    "three-dxf-master/README.md",
    "three-dxf-master/bower.json",
    "three-dxf-master/bower_components/",
    "three-dxf-master/bower_components/.DS_Store",
    "three-dxf-master/bower_components/dxf-parser/",
    "three-dxf-master/bower_components/dxf-parser/foo",
    "three-dxf-master/bower_components/dxf-parser/bar",
    "three-dxf-master/dummy_folder/",
    "three-dxf-master/dummy_folder/foo",
    "three-dxf-master/dummy_folder/hello/",
    "three-dxf-master/dummy_folder/hello/hello",
]

// Extract a filename from a path
function getFilename(path) {
    return path.split("/").filter(function(value) {
        return value && value.length;
    }).reverse()[0];
}

// Find sub paths
function findSubPaths(path) {
    // slashes need to be escaped when part of a regexp
    var rePath = path.replace("/", "\\/");
    var re = new RegExp("^" + rePath + "[^\\/]*\\/?$");
    return paths.filter(function(i) {
        return i !== path && re.test(i);
    });
}

// Build tree recursively
function buildTree(path) {
    path = path || "";
    var nodeList = [];
    findSubPaths(path).forEach(function(subPath) {
        var nodeName = getFilename(subPath);
        if (/\/$/.test(subPath)) {
            var node = {};
            node[nodeName] = buildTree(subPath);
            nodeList.push(node);
        } else {
            nodeList.push(nodeName);
        }
    });
    return nodeList;
}

// Build tree from root
var tree = buildTree();

// By default, tree is an array
// If it contains only one element which is an object, 
// return this object instead to match OP request
if (tree.length == 1 && (typeof tree[0] === 'object')) {
    tree = tree[0];
}

// Serialize tree for debug purposes
console.log(JSON.stringify(tree, null, 2));

<强>解释

function getFilename(path) {
    return path.split("/").filter(function(value) {
        return value && value.length;
    } ).reverse()
    [0];
}
  

要获取文件名,路径将被/拆分。

     

/ path / to / dir / =&gt; ['path', 'to', 'dir', '']

     

/ path / to / file =&gt; ['path', 'to', 'file']

     

仅保留具有长度的值,此句柄目录路径。

     

文件名是我们数组的最后一个值,为此我们很简单   反转数组并获取第一个元素。

function findSubPaths(path) {
    // slashes need to be escaped when part of a regexp
    var rePath = path.replace("/", "\\/");
    var re = new RegExp("^" + rePath + "[^\\/]*\\/?$");
    return paths.filter(function(i) {
        return i !== path && re.test(i);
    });
}
  

要查找路径的子路径,我们在路径列表中使用过滤器。

     

过滤器使用正则表达式(演示为available here)来测试路径是以父路径开始并以/(这是dir路径)结束还是结束line(这是一个文件路径)。

     

如果测试路径不等于父路径并且与正则表达式匹配,则过滤器接受它。否则就被拒绝了。

function buildTree(path) {
    path = path || "";
    var nodeList = [];
    findSubPaths(path).forEach(function(subPath) {
        var nodeName = getFilename(subPath);
        if(/\/$/.test(subPath)) {
            var node = {};
            node[nodeName] = buildTree(subPath);
            nodeList.push(node);            
        }
        else {
            nodeList.push(nodeName);
        }   
    });
    return nodeList;
}
  

既然我们有从路径中提取文件名并查找子路径的方法,那么构建我们的树非常容易。 Tree是一个nodeList。

     

如果子路径以/结束,则它是一个目录,我们在将节点附加到nodeList之前递归调用buildTree

     

否则我们只需将文件名添加到nodeList。

附加代码

if (tree.length == 1 && (typeof tree[0] === 'object')) {
    tree = tree[0];
}
  

默认情况下,返回的树是一个数组。

     

要匹配OP请求,如果它只包含一个作为对象的元素,那么我们将返回此对象。

答案 1 :(得分:1)

您可以将行拆分为记录,然后将每个记录拆分为字段。处理时,确定字段是目录还是文件。如果是目录,请查看它是否是子目录,如果它不存在则创建它。然后进入它。

如果它是一个文件,只需按下当前目录即可。

OP中的格式不允许根目录中的文件,因此如果遇到一个文件,则会引发错误。要允许根目录中的文件,基础对象必须是一个数组(但它似乎是一个对象)。

以下内容还允许路径以任何顺序排列并且非顺序地创建,例如,它会接受:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

它不需要:

foobar/fum

希望评论足够。

&#13;
&#13;
foobar/
foobar/fum
&#13;
&#13;
&#13;

答案 2 :(得分:0)

<强>信息

在尝试此页面中的所有解决方案后,正在寻找实施,每个都有错误。

最后我找到了this

<强>解决方案

您需要在jszip路径输出中添加“/”以使用该算法,您可以使用forEach循环。

var paths = [
    '/FolderA/FolderB/FolderC/Item1',
    '/FolderA/FolderB/Item1',
    '/FolderB/FolderD/FolderE/Item1',
    '/FolderB/FolderD/FolderE/Item2',
    '/FolderA/FolderF/Item1',
    '/ItemInRoot'
];

function arrangeIntoTree(paths, cb) {
    var tree = [];

    // This example uses the underscore.js library.
    _.each(paths, function(path) {

        var pathParts = path.split('/');
        pathParts.shift(); // Remove first blank element from the parts array.

        var currentLevel = tree; // initialize currentLevel to root

        _.each(pathParts, function(part) {

            // check to see if the path already exists.
            var existingPath = _.findWhere(currentLevel, {
                name: part
            });

            if (existingPath) {
                // The path to this item was already in the tree, so don't add it again.
                // Set the current level to this path's children
                currentLevel = existingPath.children;
            } else {
                var newPart = {
                    name: part,
                    children: [],
                }

                currentLevel.push(newPart);
                currentLevel = newPart.children;
            }
        });
    });

    cb(tree);
}

arrangeIntoTree(paths, function(tree) {
    console.log('tree: ', tree);
});

我还需要在交互式树中显示数据,我使用了angular-tree-control,它接受​​了确切的格式。