【问题标题】:Recursively load files from directory and subdirectories with require-all使用 require-all 从目录和子目录递归加载文件
【发布时间】:2019-07-11 09:26:31
【问题描述】:

我在一个目录和子目录中有我想要与特定条件匹配的 json 文件,但是我不知道如何使用子目录。

我正在使用require-all 来查找 json 文件:

const reqAll = require('require-all')({
  dirname: __dirname + '/resource',
  filter: /(.+)\.json$/,
  recursive: true
});

我的文件树是这样的:

MyDir
- file1.json
- SubDir
-- file2.json

打印reqAll会输出:

{ 
  file1: { 
    path: /first,
    body: ...some body
  },
  SubDir: { 
    file2: { 
      path: /second,
      body: ...some body
    } 
  } 
}

我最初使用以下过滤器来清除我的数据,因为我最初不使用子目录,但现在它是有意义的。

let source = Object.values(reqAll).filter(r => {
    return r.path === req.url;
}

req.url 是我发送的 http 请求的 url。即:localhost:8080/first,这样它将与我目录中的 file1 文件匹配。

问题是,当我提交 localhost:8080/second 时,我没有收到响应,因为我无法匹配到 file2,因为它位于子目录中。发送localhost:8080/SubDir/file2 也不起作用。

有什么方法可以让它工作吗?

【问题讨论】:

  • @T.J.Crowder - 当我说Printing... 时,我的意思是实际打印变量reqAll。如果对于过滤器,我将其简单地打印在那里,它只会输出文件名。
  • 忽略我。我的子目录名为x,我设法在输出中忽略了它。我得到和你一样的输出。 :-)
  • 我不太清楚你想用这些 JSON 文件做什么。 path 属性是否应该是您为 HTTP 服务器定义的路径? (例如,使用 ExpressJS 或 Koa 或...)然后您在处理该请求时使用同一对象(其中包含 path 的对象)中的其他数据?
  • @T.J.Crowder - 所以,我将在 localhost:8080/first 上执行 HTTP GET,它应该返回 file1 对象的主体。这实际上适用于这个端点。但是,当我在 localhost:8080/second 上执行 HTTP GET 时,我无法取回正文。这是因为let source... 部分。假设每个新对象都以文件名开头,并且正下方有path 属性,而我们可以看到第二个对象以目录名开头,正下方只有文件名。 path 属性隐藏在对象的第二层中。

标签: javascript recursion path


【解决方案1】:

在您写的评论中:

所以,我将在 localhost:8080/first 上执行 HTTP GET,它应该返回 file1 对象的主体。这实际上适用于这个端点。但是,当我在 localhost:8080/second 上执行 HTTP GET 时,我无法取回正文。

为此,您需要递归搜索带有 path 的条目,类似于以下内容(请参阅 cmets):

const repAll = { 
    file1: { 
        path: "/first"
    },
    SubDir: { 
        file2: { 
            path: "/second"
        },
        SubSubDir: {
            file3: {
                path: "/third"
            }
        }
    } 
};
const req = {};

function findEntry(data, path) {
    for (const value of Object.values(data)) {
        // Is this a leaf node or a container?
        if (value.path) {
            // Leaf, return it if it's a match
            if (value.path === path) {
                return value;
            }
        } else {
            // Container, look inside it recursively
            const entry = findEntry(value, path);
            if (entry) {
                return entry;
            }
        }
    }
    return undefined; // Just to be explicit
}

for (const url of ["/first", "/second", "/third", "fourth"]) {
    req.url = url;
    console.log(req.url + ":", findEntry(repAll, req.url));
}
.as-console-wrapper {
    max-height: 100% !important;
}

我添加了第二个子目录以确保递归继续工作,并添加了一个示例,说明如果找不到匹配的路径会返回什么。

当然,您可以通过预先处理一次repAll 来构建地图,然后重复使用该地图,这将比这种线性搜索更快:

const repAll = { 
    file1: { 
        path: "/first"
    },
    SubDir: { 
        file2: { 
            path: "/second"
        },
        SubSubDir: {
            file3: {
                path: "/third"
            }
        }
    } 
};

const byPath = new Map();
function indexEntries(map, data) {
    for (const value of Object.values(data)) {
        if (value) {
            // Leaf or container?
            if (value.path) {
                map.set(value.path, value);
            } else {
                indexEntries(map, value);
            }
        }
    }
}
indexEntries(byPath, repAll);

const req = {};
for (const url of ["/first", "/second", "/third", "fourth"]) {
    req.url = url;
    console.log(req.url + ":", byPath.get(req.url));
}
.as-console-wrapper {
    max-height: 100% !important;
}

【讨论】:

  • 太棒了!我现在还是一个大三学生,所以当人们对我说“递归”时,我对 XD 视而不见。但是您的代码现在对我来说实际上很有意义!感谢TJ的帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-05
  • 1970-01-01
  • 1970-01-01
  • 2022-09-26
  • 1970-01-01
  • 2021-05-25
  • 2011-05-05
相关资源
最近更新 更多