树结构未按预期构建
Tree structure not building as expected
我正在尝试编写一个函数来从给定的起始目录创建树。换句话说,我选择一个目录,然后该函数绝对映射该特定目录中的所有内容。我以前从未做过这样的事情,但我接近预期的输出。但是,我不确定我哪里出错了。
起始目录
> Test Root
> 1a
> 1b
> 2a
> 2b
> 2c
> 1c
> 2a
> 1d
> 2a
> 2b
> testfile.txt
输出
第一关很好。第二层几乎可以使用了,但由于某种原因,它复制了 parent
属性 并创建了一个额外的嵌套对象。它还总是插入 type
属性。我试过删除 constructor
中的属性,但输出同样令人困惑。
{
"parent": null,
"path": "C:\Users\Anthony\Desktop\Test Root",
"name": "Test Root",
"kids": [
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\1a",
"name": "1a",
"kids": []
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\1b",
"name": "1b",
"kids": [
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1b",
"path": "C:\Users\Anthony\Desktop\Test Root\1b\2a",
"name": "2a",
"kids": []
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1b",
"path": "C:\Users\Anthony\Desktop\Test Root\1b\2b",
"name": "2b",
"kids": []
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1b",
"path": "C:\Users\Anthony\Desktop\Test Root\1b\2c",
"name": "2c",
"kids": []
},
"type": "fileType"
}
]
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\1c",
"name": "1c",
"kids": [
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1c",
"path": "C:\Users\Anthony\Desktop\Test Root\1c\2a",
"name": "2a",
"kids": []
},
"type": "fileType"
}
]
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\1d",
"name": "1d",
"kids": [
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1d",
"path": "C:\Users\Anthony\Desktop\Test Root\1d\2a",
"name": "2a",
"kids": []
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1d",
"path": "C:\Users\Anthony\Desktop\Test Root\1d\2b",
"name": "2b",
"kids": []
},
"type": "fileType"
}
]
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\testfile.txt",
"name": "testfile.txt",
"type": "fileType"
},
"type": "fileType"
}
]
}
函数
async function createTree(root){
const
Node = class {
constructor(parent, path, name, fifo){
this.parent = parent
this.path = path
this.name = name
fifo ? this.kids = [] : this.type = 'fileType'
}
addChild(parent, path, name, fifo){
this.kids.push(new Node(parent, path, name, fifo))
}
},
traverse = async function(node, path){
const childPaths = await fsp.readdir(path)
for (const childPath of childPaths){
const
name = childPath,
stats = await fsp.stat(join(path, childPath))
let
fifo
if (stats.isDirectory()) fifo = 1
else if (stats.isFile()) fifo = 0
const
childNode = new Node(path, join(path, childPath), name, fifo)
node.addChild(childNode)
traverse(childNode, join(path, childPath))
}
},
rootName = root.slice(-1) === '\' ? root.slice(0,1) : root.slice(root.lastIndexOf('\')+1),
tree = new Node(null, root, rootName, 1)
traverse(tree, root)
setTimeout(function(){
console.log(JSON.stringify(tree, null, 2))
}, 2500)
}
我刚刚意识到我的异步函数没有返回任何东西。明天我将不得不检查所有这些。
问题是您在这里只将第一个参数传递给 addChild
函数。
addChild
函数需要提供 4 个参数。然而:
node.addChild(childNode)
// is approximately equivalent to:
addChild ( Node {...}, undefined, undefined, undefined)
你应该这样调用函数:
node.addChild(childNode.path, childNode.path, childNode.name, childNode.fifo)
你在逻辑上走在正确的道路上,接近一个很好的递归解决方案,但我认为 class 有点矫枉过正,对于像这样的功能性问题来说太面向对象了。这是一个功能更强大的版本的快速示例,它应该会给您预期的结果:
const nodePath = require('path');
const fs = require('fs');
/**
* Supply an `fs` function and it will turn it into a promisified version
* @param {Function} fn The function to promisify. This means you do not
* need the `fsp` library.
*/
function promisify (fn) {
return (...args) => new Promise((resolve, reject) => fn(...args, (err, data) => err ? reject(err) : resolve(data)));
};
// Create promisified versions of `fs.stat` and `fs.readdir`
const stat = promisify(fs.stat);
const readdir = promisify(fs.readdir);
function createDirectory (parent, path, name, kids) {
return { parent, path, name, kids: kids || [] };
};
function createFile (parent, path, name) {
return { parent, path, name, type: 'fileType' };
}
// The main recursive function.
async function createTree (parent, path) {
let stats = await stat(path);
if (stats.isDirectory()) {
const children = await readdir(path);
// Because each recursive call retruns a promise, we want to continue only when
// all of them have resolved. So we use Promise.all for this.
let child_nodes = await Promise.all(
children.map(child => createTree(path, nodePath.join(path, child)))
);
// Create a directory node
return createDirectory(parent, path, nodePath.basename(path), child_nodes);
}
// Create a file node
return createFile(parent, path, nodePath.basename(path));
};
// Startup code, can use your own stuff here.
async function start () {
let tree = await createTree(null, '/home/james/Whosebug/58706769/Test Root');
console.log(JSON.stringify(tree, null, 2));
}
start();
运行 这个文件在 Node 中,我得到以下输出:
{
"parent": null,
"path": "/home/james/Whosebug/58706769/Test Root",
"name": "Test Root",
"kids": [
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/1a",
"name": "1a",
"kids": []
},
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/1b",
"name": "1b",
"kids": [
{
"parent": "/home/james/Whosebug/58706769/Test Root/1b",
"path": "/home/james/Whosebug/58706769/Test Root/1b/2a",
"name": "2a",
"kids": []
},
{
"parent": "/home/james/Whosebug/58706769/Test Root/1b",
"path": "/home/james/Whosebug/58706769/Test Root/1b/2b",
"name": "2b",
"kids": []
},
{
"parent": "/home/james/Whosebug/58706769/Test Root/1b",
"path": "/home/james/Whosebug/58706769/Test Root/1b/2c",
"name": "2c",
"kids": []
}
]
},
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/1c",
"name": "1c",
"kids": [
{
"parent": "/home/james/Whosebug/58706769/Test Root/1c",
"path": "/home/james/Whosebug/58706769/Test Root/1c/2a",
"name": "2a",
"kids": []
}
]
},
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/1d",
"name": "1d",
"kids": [
{
"parent": "/home/james/Whosebug/58706769/Test Root/1d",
"path": "/home/james/Whosebug/58706769/Test Root/1d/2a",
"name": "2a",
"kids": []
},
{
"parent": "/home/james/Whosebug/58706769/Test Root/1d",
"path": "/home/james/Whosebug/58706769/Test Root/1d/2b",
"name": "2b",
"kids": []
}
]
},
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/testfile.txt",
"name": "testfile.txt",
"type": "fileType"
}
]
}
我正在尝试编写一个函数来从给定的起始目录创建树。换句话说,我选择一个目录,然后该函数绝对映射该特定目录中的所有内容。我以前从未做过这样的事情,但我接近预期的输出。但是,我不确定我哪里出错了。
起始目录
> Test Root
> 1a
> 1b
> 2a
> 2b
> 2c
> 1c
> 2a
> 1d
> 2a
> 2b
> testfile.txt
输出
第一关很好。第二层几乎可以使用了,但由于某种原因,它复制了 parent
属性 并创建了一个额外的嵌套对象。它还总是插入 type
属性。我试过删除 constructor
中的属性,但输出同样令人困惑。
{
"parent": null,
"path": "C:\Users\Anthony\Desktop\Test Root",
"name": "Test Root",
"kids": [
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\1a",
"name": "1a",
"kids": []
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\1b",
"name": "1b",
"kids": [
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1b",
"path": "C:\Users\Anthony\Desktop\Test Root\1b\2a",
"name": "2a",
"kids": []
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1b",
"path": "C:\Users\Anthony\Desktop\Test Root\1b\2b",
"name": "2b",
"kids": []
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1b",
"path": "C:\Users\Anthony\Desktop\Test Root\1b\2c",
"name": "2c",
"kids": []
},
"type": "fileType"
}
]
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\1c",
"name": "1c",
"kids": [
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1c",
"path": "C:\Users\Anthony\Desktop\Test Root\1c\2a",
"name": "2a",
"kids": []
},
"type": "fileType"
}
]
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\1d",
"name": "1d",
"kids": [
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1d",
"path": "C:\Users\Anthony\Desktop\Test Root\1d\2a",
"name": "2a",
"kids": []
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root\1d",
"path": "C:\Users\Anthony\Desktop\Test Root\1d\2b",
"name": "2b",
"kids": []
},
"type": "fileType"
}
]
},
"type": "fileType"
},
{
"parent": {
"parent": "C:\Users\Anthony\Desktop\Test Root",
"path": "C:\Users\Anthony\Desktop\Test Root\testfile.txt",
"name": "testfile.txt",
"type": "fileType"
},
"type": "fileType"
}
]
}
函数
async function createTree(root){
const
Node = class {
constructor(parent, path, name, fifo){
this.parent = parent
this.path = path
this.name = name
fifo ? this.kids = [] : this.type = 'fileType'
}
addChild(parent, path, name, fifo){
this.kids.push(new Node(parent, path, name, fifo))
}
},
traverse = async function(node, path){
const childPaths = await fsp.readdir(path)
for (const childPath of childPaths){
const
name = childPath,
stats = await fsp.stat(join(path, childPath))
let
fifo
if (stats.isDirectory()) fifo = 1
else if (stats.isFile()) fifo = 0
const
childNode = new Node(path, join(path, childPath), name, fifo)
node.addChild(childNode)
traverse(childNode, join(path, childPath))
}
},
rootName = root.slice(-1) === '\' ? root.slice(0,1) : root.slice(root.lastIndexOf('\')+1),
tree = new Node(null, root, rootName, 1)
traverse(tree, root)
setTimeout(function(){
console.log(JSON.stringify(tree, null, 2))
}, 2500)
}
我刚刚意识到我的异步函数没有返回任何东西。明天我将不得不检查所有这些。
问题是您在这里只将第一个参数传递给 addChild
函数。
addChild
函数需要提供 4 个参数。然而:
node.addChild(childNode)
// is approximately equivalent to:
addChild ( Node {...}, undefined, undefined, undefined)
你应该这样调用函数:
node.addChild(childNode.path, childNode.path, childNode.name, childNode.fifo)
你在逻辑上走在正确的道路上,接近一个很好的递归解决方案,但我认为 class 有点矫枉过正,对于像这样的功能性问题来说太面向对象了。这是一个功能更强大的版本的快速示例,它应该会给您预期的结果:
const nodePath = require('path');
const fs = require('fs');
/**
* Supply an `fs` function and it will turn it into a promisified version
* @param {Function} fn The function to promisify. This means you do not
* need the `fsp` library.
*/
function promisify (fn) {
return (...args) => new Promise((resolve, reject) => fn(...args, (err, data) => err ? reject(err) : resolve(data)));
};
// Create promisified versions of `fs.stat` and `fs.readdir`
const stat = promisify(fs.stat);
const readdir = promisify(fs.readdir);
function createDirectory (parent, path, name, kids) {
return { parent, path, name, kids: kids || [] };
};
function createFile (parent, path, name) {
return { parent, path, name, type: 'fileType' };
}
// The main recursive function.
async function createTree (parent, path) {
let stats = await stat(path);
if (stats.isDirectory()) {
const children = await readdir(path);
// Because each recursive call retruns a promise, we want to continue only when
// all of them have resolved. So we use Promise.all for this.
let child_nodes = await Promise.all(
children.map(child => createTree(path, nodePath.join(path, child)))
);
// Create a directory node
return createDirectory(parent, path, nodePath.basename(path), child_nodes);
}
// Create a file node
return createFile(parent, path, nodePath.basename(path));
};
// Startup code, can use your own stuff here.
async function start () {
let tree = await createTree(null, '/home/james/Whosebug/58706769/Test Root');
console.log(JSON.stringify(tree, null, 2));
}
start();
运行 这个文件在 Node 中,我得到以下输出:
{
"parent": null,
"path": "/home/james/Whosebug/58706769/Test Root",
"name": "Test Root",
"kids": [
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/1a",
"name": "1a",
"kids": []
},
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/1b",
"name": "1b",
"kids": [
{
"parent": "/home/james/Whosebug/58706769/Test Root/1b",
"path": "/home/james/Whosebug/58706769/Test Root/1b/2a",
"name": "2a",
"kids": []
},
{
"parent": "/home/james/Whosebug/58706769/Test Root/1b",
"path": "/home/james/Whosebug/58706769/Test Root/1b/2b",
"name": "2b",
"kids": []
},
{
"parent": "/home/james/Whosebug/58706769/Test Root/1b",
"path": "/home/james/Whosebug/58706769/Test Root/1b/2c",
"name": "2c",
"kids": []
}
]
},
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/1c",
"name": "1c",
"kids": [
{
"parent": "/home/james/Whosebug/58706769/Test Root/1c",
"path": "/home/james/Whosebug/58706769/Test Root/1c/2a",
"name": "2a",
"kids": []
}
]
},
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/1d",
"name": "1d",
"kids": [
{
"parent": "/home/james/Whosebug/58706769/Test Root/1d",
"path": "/home/james/Whosebug/58706769/Test Root/1d/2a",
"name": "2a",
"kids": []
},
{
"parent": "/home/james/Whosebug/58706769/Test Root/1d",
"path": "/home/james/Whosebug/58706769/Test Root/1d/2b",
"name": "2b",
"kids": []
}
]
},
{
"parent": "/home/james/Whosebug/58706769/Test Root",
"path": "/home/james/Whosebug/58706769/Test Root/testfile.txt",
"name": "testfile.txt",
"type": "fileType"
}
]
}