Alle bestanden in een map lezen, ze opslaan in objecten en het object verzenden

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 promiseAlldoet de magie. Er is een functieblok van handtekening nodig function(item,index,resolve,reject), waarbij itemis het huidige item in de array, indexDe positie ervan in de array, en resolveEN rejectDe PromiseCALLBACK-functies.
Elke belofte wordt in een array gedrukt in de huidige indexen met de huidige itemals 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 undefinedvoor 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 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)
}          

Other episodes