Как составить список содержимого каталога В ПОРЯДКЕ с помощью node.js? - PullRequest
12 голосов
/ 06 июня 2011

Я довольно опытный программист, и я недавно обнаружил node.js. Я люблю JavaScript, потому что это то, с чего я начал (веб-разработка), поэтому возможность писать код на стороне сервера с его помощью просто поражает.

В настоящее время я работаю над простым упражнением, сервером 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);
  });
});

А вот вывод в браузере: Output in Browser

** РЕШИТЬ: **

Благодаря @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);

Вывод браузера: Problem Solved Постскриптум Я удалю 'is dir' и 'is file'. Они были только для тестирования.

1 Ответ

13 голосов
/ 06 июня 2011

Если вы хотите, чтобы они упорядочивались по имени, вы можете сначала вызвать 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.localCompare(b);
}).forEach(printBr);

Метод localCompare - это то, что метод sort использует по умолчанию в качестве функции сравнения, поэтому мы делегируем это, если они оба на «равных» условиях. Вы можете расширить это по мере необходимости. Я также рекомендую вам сохранить результат isDirectory на карте или как минимум что-нибудь еще. Кроме того, statSync подходит для демонстрационных целей, но не в рабочем коде. Используйте взамен stat. Это приводит к несколько более сложному коду, но преимущества асинхронного поведения того стоят.

...