【问题标题】:How to list contents of a directory IN ORDER with node.js?如何使用 node.js 按顺序列出目录的内容?
【发布时间】:2011-09-08 22:17:02
【问题描述】:

我是一位经验丰富的程序员,我最近才发现了 node.js。我喜欢 JavaScript,因为那是我开始的地方(Web 开发),所以能够用它编写服务器端代码真是太棒了。

目前,我正在做一个简单的练习,一个 WebSocket/HTTP 服务器,当我遇到一个小烦恼时,我开始添加目录列表功能:当我列出某个目录中的目录和文件时,它们是没有任何顺序。我希望它们首先列出目录,然后按字母顺序列出文件(如“ls”命令)。我有一种感觉,因为它是异步的,但我并不完全积极。任何帮助将不胜感激。

顺便说一句,这是我的代码:

var sys = require("sys");
var ws = require('websocket-server');
var fs = require("fs");
var path = require("path");
var url = require("url");

function log(data){
  sys.log("\033[0;32m"+data+"\033[0m");
}

var server = ws.createServer();
server.listen(3400);
log("Listening on 3400 for HTTP and WS");

server.addListener("request", function(request, response){
  log("HTTP: Connected: " + request.connection.remoteAddress);
  var uri = url.parse(request.url).pathname;
  var filename = path.join("/home/brandon", uri);
  log("HTTP: " + request.connection.remoteAddress + " Requested: " + filename);
  path.exists(filename, function(exists) {
        if(!exists) {
            response.writeHead(404, {"Content-Type": "text/plain"});
            response.write("404 Not Found\n");
            log("HTTP: " + filename + " Does Not Exist. 404 returned to " + request.connection.remoteAddress);
            response.end();
            log("HTTP: Disconnected: " + request.connection.remoteAddress);
            return;
        }

        fs.readFile(filename, "binary", function(err, file) {
            if(err) {
                if(err.errno === 21){
                    fs.readdir(filename, function(err1, files){
                        if(err1){ 
                            response.writeHead(500, {"Content-Type": "text/plain"});
                            response.write("Error when reading directory: " + err1 + "\n");
                            log("HTTP: " + filename + " Could Not Be Read. 500 returned to " + request.connection.remoteAddress);
                            response.end();
                            log("HTTP: Disconnected: " + request.connection.remoteAddress);
                            return;
                        } else {
                            response.writeHead(200);
                            response.write("<HTML><HEAD><title>Directory Listing for " + uri + "</title></HEAD><BODY><h1>Directory Listing for " + uri + "</h1>");
                            response.write("<ul>");
                            function printBr(element, index, array) {
                                response.write("<li>" + element + "</li>");
                            }
                            /*for( i in files ){
                                response.write("<li>" + files[i] + "</li>");
                            }*/
                            files.forEach(printBr);
                            response.write("</ul>");
                            response.write("</BODY></HTML>");
                            log("HTTP: Directory listing for " + filename + " sent to " + request.connection.remoteAddress);
                            response.end();
                            log("HTTP: Disconnected: " + request.connection.remoteAddress);
                            return;
                        }
                    });
                    return;
                }
                response.writeHead(500, {"Content-Type": "text/plain"});
                response.write("Error when reading file: " + err + "\n");
                log("HTTP: " + filename + " Could Not Be Read. 500 returned to " + request.connection.remoteAddress);
                response.end();
                log("HTTP: Disconnected: " + request.connection.remoteAddress);
                return;
            }

            response.writeHead(200);
            response.write(file, "binary");
            log("HTTP: " + filename + " Read and Sent to " + request.connection.remoteAddress);
            response.end();
            log("HTTP: Disconnected: " + request.connection.remoteAddress);
        });
    });
});

server.addListener("connection", function(conn){
  log(conn.id + ": new connection");
  server.broadcast("New Connection: "+conn.id);
  conn.addListener("readyStateChange", function(readyState){
    log("stateChanged: "+readyState);
  });

  conn.addListener("close", function(){
    var c = this;
    log(c.id + ": Connection Closed");
    server.broadcast("Connection Closed: "+c.id);
  });

  conn.addListener("message", function(message){
    log(conn.id + ": "+JSON.stringify(message));

    server.broadcast(conn.id + ": "+message);
  });
});

这是浏览器中的输出:

**已解决:**

感谢@Samir,我知道了如何做我想做的事。我遍历目录内容的数组,检查一个项目是目录还是文件,将它们分成两个数组('dirs_in' 用于 dirs 和 'files_in' 用于文件),按字母顺序对两个数组进行排序,最后将它们写出来.

代码(第 42-70 行):

response.writeHead(200);
response.write("<HTML><HEAD><title>Directory Listing for " + uri + "</title></HEAD><BODY><h1>Directory Listing for " + uri + "</h1>");
response.write("<ul>");
function printBr(element, index, array) {
    response.write("<li>" + element);
    if( fs.statSync( path.join(filename + element) ).isDirectory() ){
        response.write(" is a <b>dir</b>");
    } else {
        response.write(" is a <b>file</b>");
    }
    response.write("</li>");
}
var dirs_in = [];
var files_in = [];
function sep(element, index, array) {
    if( fs.statSync( path.join(filename + element) ).isDirectory() ){
        dirs_in.push(element);
    } else {
        files_in.push(element);
    }
}
files.forEach(sep);
dirs_in.sort().forEach(printBr);
files_in.sort().forEach(printBr);
response.write("</ul>");
response.write("</BODY></HTML>");
log("HTTP: Directory listing for " + filename + " sent to " + request.connection.remoteAddress);
response.end();
log("HTTP: Disconnected: " + request.connection.remoteAddress);

浏览器输出: 附言我将删除“是目录”和“是文件”。它们只是为了测试。

【问题讨论】:

  • 即使回答了这个问题,也许您可​​以定义“按顺序”列出目录中的文件意味着什么?
  • statSync 并不便宜,并且会在您的代码中造成可怕的瓶颈。不要在 Web 服务器中使用 Sync 函数。
  • 您可以尝试here7 给出的解决方案 为什么要重建轮子? ;)

标签: javascript list node.js directory inorder


【解决方案1】:

如果您希望它们按名称排序,您可以先在数组上调用sort()

files.sort().forEach(printBr);

例如,如果您想先对目录进行排序,那么您需要获取更多信息。一个简单的实现是在排序比较函数中查询每个文件的统计信息:

files.sort(function(a, b) {
    var aIsDir = fs.statSync(dir + "/" + a).isDirectory(),
        bIsDir = fs.statSync(dir + "/" + b).isDirectory();
    
    if (aIsDir && !bIsDir) {
        return -1;
    }

    if (!aIsDir && bIsDir) {
        return 1;
    }

    return a.localeCompare(b);
}).forEach(printBr);

localeCompare 方法是 sort 方法默认使用的比较函数,因此如果它们都处于“相等”的条件下,我们将委托给它。您可以根据需要对此进行扩展。我还建议您至少将isDirectory 的结果存储在地图或其他东西中。此外,statSync 可用于演示目的,但不适用于生产代码。请改用stat。这确实会导致代码稍微复杂一些,但异步行为的好处是值得的。

【讨论】:

  • 这有帮助,但我想先按类型(例如目录或文件)然后按名称列出它们。这可能吗?
  • 谢谢!我在 API 的某处寻找“isDirectory”函数。
  • -1 用于使用 Sync 函数。它们造成了可怕的瓶颈。
  • @Raynos:这就是我所说的“天真”的部分含义。你如何使用异步函数将取决于你的风格和它周围的代码。在某些时候,您将不得不敲入某种闩锁,这实际上超出了此问题的范围。我将在答案中添加有关如何使用stat 的信息。
  • naive 是缓慢的或次优的。上面的代码造成了一个可怕的瓶颈,使服务器无法扩展。效率低下和关键瓶颈之间存在差异。建议使用Sync 只是一种糟糕的形式。
猜你喜欢
  • 2017-08-02
  • 1970-01-01
  • 2019-01-11
  • 2021-10-25
  • 1970-01-01
  • 2019-09-05
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多