javascript - filesystem - readfile nodejs
Caminando un directorio con Node.js (6)
Tengo un problema con este código en node.js. Quiero recorrer recursivamente un árbol de directorios y aplicar la action
devolución de llamada a cada archivo en el árbol. Este es mi código en este momento:
var fs = require("fs");
// General function
var dive = function (dir, action) {
// Assert that it''s a function
if (typeof action !== "function")
action = function (error, file) { };
// Read the directory
fs.readdir(dir, function (err, list) {
// Return the error if something went wrong
if (err)
return action(err);
// For every file in the list
list.forEach(function (file) {
// Full path of that file
path = dir + "/" + file;
// Get the file''s stats
fs.stat(path, function (err, stat) {
console.log(stat);
// If the file is a directory
if (stat && stat.isDirectory())
// Dive into the directory
dive(path, action);
else
// Call the action
action(null, path);
});
});
});
};
El problema es que en la estadística de cada bucle se llama para cada archivo a través de la path
variable. Cuando se llama a la devolución de llamada, la path
ya tiene otro valor, por lo que se dive
en los directorios incorrectos o llama a la action
de los archivos incorrectos.
Probablemente este problema podría resolverse fácilmente usando fs.statSync
, pero esta no es la solución que preferiría, ya que está bloqueando el proceso.
No estoy seguro de si realmente debería publicar esto como una respuesta, pero para su conveniencia y para otros usuarios, aquí hay una versión reescrita de OP que puede ser útil. Proporciona:
- Mejor soporte a la gestión de errores.
- Una devolución de llamada de finalización global que se llama cuando se completa la exploración
El código:
/**
* dir: path to the directory to explore
* action(file, stat): called on each file or until an error occurs. file: path to the file. stat: stat of the file (retrived by fs.stat)
* done(err): called one time when the process is complete. err is undifined is everything was ok. the error that stopped the process otherwise
*/
var walk = function(dir, action, done) {
// this flag will indicate if an error occured (in this case we don''t want to go on walking the tree)
var dead = false;
// this flag will store the number of pending async operations
var pending = 0;
var fail = function(err) {
if(!dead) {
dead = true;
done(err);
}
};
var checkSuccess = function() {
if(!dead && pending == 0) {
done();
}
};
var performAction = function(file, stat) {
if(!dead) {
try {
action(file, stat);
}
catch(error) {
fail(error);
}
}
};
// this function will recursively explore one directory in the context defined by the variables above
var dive = function(dir) {
pending++; // async operation starting after this line
fs.readdir(dir, function(err, list) {
if(!dead) { // if we are already dead, we don''t do anything
if (err) {
fail(err); // if an error occured, let''s fail
}
else { // iterate over the files
list.forEach(function(file) {
if(!dead) { // if we are already dead, we don''t do anything
var path = dir + "/" + file;
pending++; // async operation starting after this line
fs.stat(path, function(err, stat) {
if(!dead) { // if we are already dead, we don''t do anything
if (err) {
fail(err); // if an error occured, let''s fail
}
else {
if (stat && stat.isDirectory()) {
dive(path); // it''s a directory, let''s explore recursively
}
else {
performAction(path, stat); // it''s not a directory, just perform the action
}
pending--; checkSuccess(); // async operation complete
}
}
});
}
});
pending--; checkSuccess(); // async operation complete
}
}
});
};
// start exploration
dive(dir);
};
No reinvente la rueda, use y contribuya al código abierto en su lugar. Pruebe uno de los siguientes:
Otra biblioteca adecuada es filehound . Es compatible con el filtrado de archivos (si es necesario), devoluciones de llamada y promesas.
Por ejemplo:
const Filehound = require(''filehound'');
function action(file) {
console.log(`process ${file}`)
}
Filehound.create()
.find((err, files) => {
if (err) {
return console.error(`error: ${err}`);
}
files.forEach(action);
});
La biblioteca está bien documentada y proporciona numerosos ejemplos de casos de uso comunes. https://github.com/nspragg/filehound
Descargo de responsabilidad: Soy el autor.
Use node-dir para esto. Como necesita una acción separada para directorios y archivos, le daré 2 iteradores simples usando node-dir.
Recorrer de forma asíncrona los archivos de un directorio y sus subdirectorios y pasar una matriz de rutas de archivos a una devolución de llamada.
var dir = require(''node-dir'');
dir.files(__dirname, function(err, files) {
if (err) throw err;
console.log(files);
//we have an array of files now, so now we''ll iterate that array
files.forEach(function(filepath) {
actionOnFile(null, filepath);
})
});
Recorrer asíncronamente los subdirectorios de un directorio y sus subdirectorios y pasar una matriz de rutas de directorio a una devolución de llamada.
var dir = require(''node-dir'');
dir.subdirs(__dirname, function(err, subdirs) {
if (err) throw err;
console.log(subdirs);
//we have an array of subdirs now, so now we''ll iterate that array
subdirs.forEach(function(filepath) {
actionOnDir(null, filepath);
})
});
var path = dir + "/" + file;
Olvidaste hacer del path
una variable local. Ahora no se cambiará detrás de su espalda en el bucle.
function loop( ) {
var item = list.shift( );
if ( item ) {
// content of the loop
functionWithCallback( loop );
} else {
// after the loop has ended
whatever( );
}
}