javascript - Procházení souborů ve složce v Node.JS
Snažím se procházet a vybírat soubory v adresáři, ale mám nějaké potíže s jejich implementací. Jak načíst více souborů a pak je přesunout do jiné složky?
var dirname = 'C:/FolderwithFiles';
console.log("Going to get file info!");
fs.stat(dirname, function (err, stats) {
if (err) {
return console.error(err);
}
console.log(stats);
console.log("Got file info successfully!");
// Check file type
console.log("isFile ? " + stats.isFile());
console.log("isDirectory ? " + stats.isDirectory());
});
Odpověď č. 1
Starší odpověď s callbacky
Chcete použít funkci fs.readdir pro získání obsahu adresáře a funkci fs.rename pro samotné přejmenování. Obě tyto funkce mají synchronní verze, pokud potřebujete počkat, než dokončí svou práci, než spustíte následující kód.
Napsal jsem rychlý skript, který dělá to, co jste popsal.
var fs = require('fs');
var path = require('path');
// In newer Node.js versions where process is already global this isn't necessary.
var process = require("process");
var moveFrom = "/home/mike/dev/node/sonar/moveme";
var moveTo = "/home/mike/dev/node/sonar/tome"
// Loop through all the files in the temp directory
fs.readdir(moveFrom, function (err, files) {
if (err) {
console.error("Could not list the directory.", err);
process.exit(1);
}
files.forEach(function (file, index) {
// Make one pass and make the file complete
var fromPath = path.join(moveFrom, file);
var toPath = path.join(moveTo, file);
fs.stat(fromPath, function (error, stat) {
if (error) {
console.error("Error stating file.", error);
return;
}
if (stat.isFile())
console.log("'%s' is a file.", fromPath);
else if (stat.isDirectory())
console.log("'%s' is a directory.", fromPath);
fs.rename(fromPath, toPath, function (error) {
if (error) {
console.error("File moving error.", error);
} else {
console.log("Moved file '%s' to '%s'.", fromPath, toPath);
}
});
});
});
});
Otestováno na mém lokálním počítači.
node testme.js
'/home/mike/dev/node/sonar/moveme/hello' is a file.
'/home/mike/dev/node/sonar/moveme/test' is a directory.
'/home/mike/dev/node/sonar/moveme/test2' is a directory.
'/home/mike/dev/node/sonar/moveme/test23' is a directory.
'/home/mike/dev/node/sonar/moveme/test234' is a directory.
Moved file '/home/mike/dev/node/sonar/moveme/hello' to '/home/mike/dev/node/sonar/tome/hello'.
Moved file '/home/mike/dev/node/sonar/moveme/test' to '/home/mike/dev/node/sonar/tome/test'.
Moved file '/home/mike/dev/node/sonar/moveme/test2' to '/home/mike/dev/node/sonar/tome/test2'.
Moved file '/home/mike/dev/node/sonar/moveme/test23' to '/home/mike/dev/node/sonar/tome/test23'.
Moved file '/home/mike/dev/node/sonar/moveme/test234' to '/home/mike/dev/node/sonar/tome/test234'.
Aktualizace: funkce fs.promises s async/await
Inspirace odpovědí od ma11hew28 (zde zobrazeno), zde je totéž jako výše, ale s asynchronními funkcemi v fs.promises. Jak poznamenal ma11hew28, toto může mít omezení paměti oproti fs.promises.opendir přidanému ve verzi v12.12.0.
Rychlý kód níže.
//jshint esversion:8
//jshint node:true
const fs = require( 'fs' );
const path = require( 'path' );
const moveFrom = "/tmp/movefrom";
const moveTo = "/tmp/moveto";
// Make an async function that gets executed immediately
(async ()=>{
// Our starting point
try {
// Get the files as an array
const files = await fs.promises.readdir( moveFrom );
// Loop them all with the new for...of
for( const file of files ) {
// Get the full paths
const fromPath = path.join( moveFrom, file );
const toPath = path.join( moveTo, file );
// Stat the file to see if we have a file or dir
const stat = await fs.promises.stat( fromPath );
if( stat.isFile() )
console.log( "'%s' is a file.", fromPath );
else if( stat.isDirectory() )
console.log( "'%s' is a directory.", fromPath );
// Now move async
await fs.promises.rename( fromPath, toPath );
// Log because we're crazy
console.log( "Moved '%s'->'%s'", fromPath, toPath );
} // End for...of
}
catch( e ) {
// Catch anything bad that happens
console.error( "We've thrown! Whoops!", e );
}
})(); // Wrap in parenthesis and call now
Odpověď č. 2
fs.readdir(path[, options], callback) (který Mikey A. Leonetti použil ve své odpovědi) a jeho varianty (fsPromises.readdir(path[, options]) a fs.readdirSync(path[, options])) každý načte všechny položky adresáře najednou do paměti. To je vhodné pro většinu případů, ale pokud má adresář velmi mnoho položek a/nebo chcete snížit paměťovou náročnost své aplikace, můžete místo toho iterovat přes položky adresáře jednu po druhé.
Asynchronně
Adresáře jsou asynchronně iterovatelné, takže byste mohli udělat něco takového:
const fs = require('fs')
async function ls(path) {
const dir = await fs.promises.opendir(path)
for await (const dirent of dir) {
console.log(dirent.name)
}
}
ls('.').catch(console.error)
Nebo můžete přímo použít dir.read() a/nebo dir.read(callback).
Synchronně
Adresáře nejsou synchronně iterovatelné, ale můžete přímo použít dir.readSync(). Například:
const fs = require('fs')
const dir = fs.opendirSync('.')
let dirent
while ((dirent = dir.readSync()) !== null) {
console.log(dirent.name)
}
dir.closeSync()
Nebo byste mohli učinit synchronní adresáře iterovatelné. Například:
const fs = require('fs')
function makeDirectoriesSyncIterable() {
const p = fs.Dir.prototype
if (p.hasOwnProperty(Symbol.iterator)) { return }
const entriesSync = function* () {
try {
let dirent
while ((dirent = this.readSync()) !== null) { yield dirent }
} finally { this.closeSync() }
}
if (!p.hasOwnProperty(entriesSync)) { p.entriesSync = entriesSync }
Object.defineProperty(p, Symbol.iterator, {
configurable: true,
enumerable: false,
value: entriesSync,
writable: true
})
}
makeDirectoriesSyncIterable()
A pak byste mohli udělat něco takového:
const dir = fs.opendirSync('.')
for (const dirent of dir) {
console.log(dirent.name)
}
Poznámka: "V rušných procesech používejte asynchronní verze těchto volání. Synchronní verze zablokují celý proces až do dokončení, zastavují všechny spojení."
Reference:
- Dokumentace Node.js: Souborový systém:
Class fs.Dir - Zdrojový kód Node.js:
fs.Dir - GitHub: nodejs/node: Problémy: streamování/iterativní fs.readdir #583
