Ik weet niet of dit mogelijk is, maar here goes. En werken met terugbellen maakt het nog moeilijker.
Ik heb een directory met html-bestanden die ik terug wil sturen naar de client in Object chunks met node.js en socket.io.
Al mijn bestanden staan in /tmpl
Socket moet dus alle bestanden in /tmpl lezen.
voor elk bestand moet het de gegevens in een object opslaan met de bestandsnaam als sleutel en de inhoud als waarde.
var data;
// this is wrong because it has to loop trough all files.
fs.readFile(__dirname + '/tmpl/filename.html', 'utf8', function(err, html){
if(err) throw err;
//filename must be without .html at the end
data['filename'] = html;
});
socket.emit('init', {data: data});
De laatste terugroepactie is ook verkeerd. Het moet worden aangeroepen als alle bestanden in de map klaar zijn.
Maar ik weet niet hoe ik de code moet maken, weet iemand of dit mogelijk is?
Antwoord 1, autoriteit 100%
Er zijn dus drie delen. Lezen, opslaan en verzenden.
Hier is het leesgedeelte:
var fs = require('fs');
function readFiles(dirname, onFileContent, onError) {
fs.readdir(dirname, function(err, filenames) {
if (err) {
onError(err);
return;
}
filenames.forEach(function(filename) {
fs.readFile(dirname + filename, 'utf-8', function(err, content) {
if (err) {
onError(err);
return;
}
onFileContent(filename, content);
});
});
});
}
Dit is het opslaggedeelte:
var data = {};
readFiles('dirname/', function(filename, content) {
data[filename] = content;
}, function(err) {
throw err;
});
Het verzendende deel is aan jou. Misschien wilt u ze één voor één verzenden of nadat het lezen is voltooid.
Als u bestanden wilt verzenden nadat het lezen is voltooid, moet u ofwel synchronisatieversies van fs
-functies gebruiken of beloften gebruiken. Asynchrone callbacks zijn geen goede stijl.
Bovendien heb je gevraagd naar het verwijderen van een extensie. U dient de vragen één voor één te behandelen. Niemand zal alleen voor jou een complete oplossing schrijven.
Antwoord 2, autoriteit 11%
Dit is een moderne Promise
-versie van de vorige, die een Promise.all
-benadering gebruikt om alle beloften op te lossen wanneer alle bestanden zijn gelezen:
/**
* Promise all
* @author Loreto Parisi (loretoparisi at gmail dot com)
*/
function promiseAllP(items, block) {
var promises = [];
items.forEach(function(item,index) {
promises.push( function(item,i) {
return new Promise(function(resolve, reject) {
return block.apply(this,[item,index,resolve,reject]);
});
}(item,index))
});
return Promise.all(promises);
} //promiseAll
/**
* read files
* @param dirname string
* @return Promise
* @author Loreto Parisi (loretoparisi at gmail dot com)
* @see http://stackoverflow.com/questions/10049557/reading-all-files-in-a-directory-store-them-in-objects-and-send-the-object
*/
function readFiles(dirname) {
return new Promise((resolve, reject) => {
fs.readdir(dirname, function(err, filenames) {
if (err) return reject(err);
promiseAllP(filenames,
(filename,index,resolve,reject) => {
fs.readFile(path.resolve(dirname, filename), 'utf-8', function(err, content) {
if (err) return reject(err);
return resolve({filename: filename, contents: content});
});
})
.then(results => {
return resolve(results);
})
.catch(error => {
return reject(error);
});
});
});
}
Hoe het te gebruiken:
net zo eenvoudig als:
readFiles( EMAIL_ROOT + '/' + folder)
.then(files => {
console.log( "loaded ", files.length );
files.forEach( (item, index) => {
console.log( "item",index, "size ", item.contents.length);
});
})
.catch( error => {
console.log( error );
});
veronderstelde dat u nog een andere lijst met mappen hebt die u kunt herformuleren over deze lijst, aangezien de interne belofte.all elk van dan asynchroon zal oplossen:
var folders=['spam','ham'];
folders.forEach( folder => {
readFiles( EMAIL_ROOT + '/' + folder)
.then(files => {
console.log( "loaded ", files.length );
files.forEach( (item, index) => {
console.log( "item",index, "size ", item.contents.length);
});
})
.catch( error => {
console.log( error );
});
});
hoe het werkt
De promiseAll
doet de magie. Er is een functieblok van handtekening nodig function(item,index,resolve,reject)
, waarbij item
is het huidige item in de array, index
De positie ervan in de array, en resolve
EN reject
De Promise
CALLBACK-functies.
Elke belofte wordt in een array gedrukt in de huidige index
en met de huidige item
als argumenten via een anonieme functie-oproep:
promises.push( function(item,i) {
return new Promise(function(resolve, reject) {
return block.apply(this,[item,index,resolve,reject]);
});
}(item,index))
Dan zullen alle beloftes worden opgelost:
return Promise.all(promises);
3, Autoriteit 9%
Voor alle voorbeeld Hieronder moet u fs en pad modules:
const fs = require('fs');
const path = require('path');
Lees bestanden asynchroon
function readFiles(dir, processFile) {
// read directory
fs.readdir(dir, (error, fileNames) => {
if (error) throw error;
fileNames.forEach(filename => {
// get current file name
const name = path.parse(filename).name;
// get current file extension
const ext = path.parse(filename).ext;
// get current file path
const filepath = path.resolve(dir, filename);
// get information about the file
fs.stat(filepath, function(error, stat) {
if (error) throw error;
// check if the current path is a file or a folder
const isFile = stat.isFile();
// exclude folders
if (isFile) {
// callback, do something with the file
processFile(filepath, name, ext, stat);
}
});
});
});
}
Gebruik:
// use an absolute path to the folder where files are located
readFiles('absolute/path/to/directory/', (filepath, name, ext, stat) => {
console.log('file path:', filepath);
console.log('file name:', name);
console.log('file extension:', ext);
console.log('file information:', stat);
});
Lees bestanden synchroon, opslaan in array, natuurlijke sorteren
/**
* @description Read files synchronously from a folder, with natural sorting
* @param {String} dir Absolute path to directory
* @returns {Object[]} List of object, each object represent a file
* structured like so: `{ filepath, name, ext, stat }`
*/
function readFilesSync(dir) {
const files = [];
fs.readdirSync(dir).forEach(filename => {
const name = path.parse(filename).name;
const ext = path.parse(filename).ext;
const filepath = path.resolve(dir, filename);
const stat = fs.statSync(filepath);
const isFile = stat.isFile();
if (isFile) files.push({ filepath, name, ext, stat });
});
files.sort((a, b) => {
// natural sort alphanumeric strings
// https://stackoverflow.com/a/38641281
return a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' });
});
return files;
}
Gebruik:
// return an array list of objects
// each object represent a file
const files = readFilesSync('absolute/path/to/directory/');
Bestanden async lezen met belofte
Meer informatie over belovenin deze artikel.
const { promisify } = require('util');
const readdir_promise = promisify(fs.readdir);
const stat_promise = promisify(fs.stat);
function readFilesAsync(dir) {
return readdir_promise(dir, { encoding: 'utf8' })
.then(filenames => {
const files = getFiles(dir, filenames);
return Promise.all(files);
})
.catch(err => console.error(err));
}
function getFiles(dir, filenames) {
return filenames.map(filename => {
const name = path.parse(filename).name;
const ext = path.parse(filename).ext;
const filepath = path.resolve(dir, filename);
return stat({ name, ext, filepath });
});
}
function stat({ name, ext, filepath }) {
return stat_promise(filepath)
.then(stat => {
const isFile = stat.isFile();
if (isFile) return { name, ext, filepath, stat };
})
.catch(err => console.error(err));
}
Gebruik:
readFiles('absolute/path/to/directory/')
// return an array list of objects
// each object is a file
// with those properties: { name, ext, filepath, stat }
.then(files => console.log(files))
.catch(err => console.log(err));
Opmerking:retourneer undefined
voor mappen, als je wilt, kun je ze eruit filteren:
readFiles('absolute/path/to/directory/')
.then(files => files.filter(file => file !== undefined))
.catch(err => console.log(err));
Antwoord 4, autoriteit 3%
Ben je een lui persoon zoals ik en hou je van npm-module😀 kijk dan eens hier.
npm installeer node-dir
voorbeeld voor het lezen van bestanden:
var dir = require('node-dir');
dir.readFiles(__dirname,
function(err, content, next) {
if (err) throw err;
console.log('content:', content); // get content of files
next();
},
function(err, files){
if (err) throw err;
console.log('finished reading files:', files); // get filepath
});
Antwoord 5, autoriteit 2%
Een andere versie met de moderne methode van Promise. Het is korter dan de antwoorden van de anderen op basis van Promise:
const readFiles = (dirname) => {
const readDirPr = new Promise( (resolve, reject) => {
fs.readdir(dirname,
(err, filenames) => (err) ? reject(err) : resolve(filenames))
});
return readDirPr.then( filenames => Promise.all(filenames.map((filename) => {
return new Promise ( (resolve, reject) => {
fs.readFile(dirname + filename, 'utf-8',
(err, content) => (err) ? reject(err) : resolve(content));
})
})).catch( error => Promise.reject(error)))
};
readFiles(sourceFolder)
.then( allContents => {
// handle success treatment
}, error => console.log(error));
6, Autoriteit 2%
Als u Node.js 8 of hoger, kunt u de nieuwe util.promisify gebruiken. (Ik ben markeren als optionele de delen van de code die te maken hebben met het opnieuw formatteren als een object, die het oorspronkelijke bericht aangevraagd.)
const fs = require('fs');
const { promisify } = require('util');
let files; // optional
promisify(fs.readdir)(directory).then((filenames) => {
files = filenames; // optional
return Promise.all(filenames.map((filename) => {
return promisify(fs.readFile)(directory + filename, {encoding: 'utf8'});
}));
}).then((strArr) => {
// optional:
const data = {};
strArr.forEach((str, i) => {
data[files[i]] = str;
});
// send data here
}).catch((err) => {
console.log(err);
});
7
Voor de code smoothy werken in verschillende omgevingen, path.resolve b>kan worden gebruikt op plaatsen waar de baan wordt gemanipuleerd. Hier is de code die beter werkt.
Reading deel:
var fs = require('fs');
function readFiles(dirname, onFileContent, onError) {
fs.readdir(dirname, function(err, filenames) {
if (err) {
onError(err);
return;
}
filenames.forEach(function(filename) {
fs.readFile(path.resolve(dirname, filename), 'utf-8', function(err, content) {
if (err) {
onError(err);
return;
}
onFileContent(filename, content);
});
});
});
}
Het opslaan van deel:
var data = {};
readFiles(path.resolve(__dirname, 'dirname/'), function(filename, content) {
data[filename] = content;
}, function(error) {
throw err;
});
8
async / af te wachten
const { promisify } = require("util")
const directory = path.join(__dirname, "/tmpl")
const pathnames = promisify(fs.readdir)(directory)
try {
async function emitData(directory) {
let filenames = await pathnames
var ob = {}
const data = filenames.map(async function(filename, i) {
if (filename.includes(".")) {
var storedFile = promisify(fs.readFile)(directory + `\\${filename}`, {
encoding: "utf8",
})
ob[filename.replace(".js", "")] = await storedFile
socket.emit("init", { data: ob })
}
return ob
})
}
emitData(directory)
} catch (err) {
console.log(err)
}
Wie wil proberen met generatoren?
9
In dit voorbeeld maak ik een array. Maar u kunt een object maken als u wilt
const fs = require('fs-extra')
const dirname = `${process.cwd()}/test`
const fileNames = await fs.readdir(dirname)
const files = []
for(const fileName of fileNames){
const file = await fs.readFile(`${dirname}/${fileName}`, 'utf8')
files.push(file)
}