je veux télécharger un fichier pdf avec axios
et enregistrer sur le disque (côté serveur) avec fs.writeFile
, j'ai essayé:
axios.get('https://xxx/my.pdf', {responseType: 'blob'}).then(response => { fs.writeFile('/temp/my.pdf', response.data, (err) => { if (err) throw err; console.log('The file has been saved!'); }); });
le fichier est enregistré mais le contenu est cassé ...
comment enregistrer correctement le fichier?
8 Réponses :
Ceci est mon exemple de code exécuté avec le nœud js Il y a une erreur de synctaxe
doit être writeFile et non WriteFile
%PDF-1.3 %���� 1 0 obj << /Type /Catalog /Outlines 2 0 R /Pages 3 0 R >> endobj 2 0 obj << /Type /Outlines /Count 0 >> endobj 3 0 obj << /Type /Pages /Count 2 /Kids [ 4 0 R 6 0 R ] >> endobj
Une fois le fichier enregistré, il peut ressembler à un éditeur de texte, mais le fichier a été enregistré correctement
const axios = require('axios'); const fs = require('fs'); axios.get('http://www.africau.edu/images/default/sample.pdf', {responseType: 'blob'}).then(response => { fs.writeFile('./my.pdf', response.data, (err) => { if (err) throw err; console.log('The file has been saved!'); }); });
Comment est-ce une réponse? Vous n'avez rien expliqué de différent de ce que le PO a publié.
node fileSystem writeFile
encode les données par défaut en UTF8. ce qui pourrait être un problème dans votre cas.
Essayez de définir votre encodage sur null
et ignorez l'encodage des données reçues:
fs.writeFile('/temp/my.pdf', response.data, 'null', (err) => {...}
vous pouvez également décaler l'encodage en tant que chaîne (au lieu de l'objet d'options) si vous ne déclarez que l'encodage et aucune autre option. string sera traité comme valeur d'encodage. En tant que tel:
fs.writeFile('/temp/my.pdf', response.data, {encoding: null}, (err) => {...}
lire plus dans fileSystem API write_file
Bien que ce code puisse résoudre la question, inclure une explication sur comment et pourquoi cela résout le problème aiderait vraiment à améliorer la qualité de votre publication et entraînerait probablement plus de votes à la hausse. N'oubliez pas que vous répondez à la question des lecteurs à l'avenir, pas seulement à la personne qui la pose maintenant. Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limites et des hypothèses applicables.
@ double bip tnx pour votre commentaire. J'ai édité avec quelques explications et lu du matériel à partir de l' node fileSystem API
sur la fonction writeFile. :)
Vous pouvez simplement utiliser response.data.pipe
et fs.createWriteStream
pour fs.createWriteStream
réponse vers le fichier
axios({ method: "get", url: "https://xxx/my.pdf", responseType: "stream" }).then(function (response) { response.data.pipe(fs.createWriteStream("/temp/my.pdf")); });
Merci beaucoup!! Je cherchais ça pour toujours
Cette réponse n'est pas complète, car lorsque vous téléchargez des fichiers plus volumineux, le tube vous donnera plus d'un événement. Ce code n'attend pas que tout le fichier ait été téléchargé avant de pouvoir l'appeler then
. Jetez un œil à ma solution pour trouver ce que je considère comme une solution plus complète.
response.data.pipe n'est pas une fonction
J'ai essayé, et je suis sûr que l'utilisation de response.data.pipe
et fs.createWriteStream
peut fonctionner.
En plus, je veux ajouter ma situation et ma solution
Situation:
koa
pour développer un serveur node.jsaxios
pour obtenir un pdf via urlpdf-parse
pour analyser le pdfSolution:
const Koa = require('koa'); const app = new Koa(); const axios = require('axios') const fs = require("fs") const pdf = require('pdf-parse'); const utils = require('./utils') app.listen(process.env.PORT || 3000) app.use(async (ctx, next) => { let url = 'https://path/name.pdf' let resp = await axios({ url: encodeURI(url), responseType: 'arraybuffer' }) let data = await pdf(resp.data) ctx.body = { phone: utils.getPhone(data.text), email: utils.getEmail(data.text), } })
Dans cette solution, il n'est pas nécessaire d'écrire et de lire un fichier, c'est plus efficace.
// This works perfectly well! const axios = require('axios'); axios.get('http://www.sclance.com/pngs/png-file-download/png_file_download_1057991.png', {responseType: "stream"} ) .then(response => { // Saving file to working directory response.data.pipe(fs.createWriteStream("todays_picture.png")); }) .catch(error => { console.log(error); });
Bienvenue dans StackOverflow! Vous voudrez peut-être fournir quelques explications pour accompagner votre exemple de code.
En fait, je pense que la réponse précédemment acceptée a quelques défauts, car elle ne gérera pas correctement le flux d'écriture, donc si vous appelez "then ()" après qu'Axios vous a donné la réponse, vous finirez par avoir un fichier partiellement téléchargé.
C'est une solution plus appropriée lors du téléchargement de fichiers légèrement plus volumineux:
export async function downloadFile(fileUrl: string, outputLocationPath: string) { const writer = createWriteStream(outputLocationPath); return Axios({ method: 'get', url: fileUrl, responseType: 'stream', }).then(response => { //ensure that the user can call `then()` only when the file has //been downloaded entirely. return new Promise((resolve, reject) => { response.data.pipe(writer); let error = null; writer.on('error', err => { error = err; writer.close(); reject(err); }); writer.on('close', () => { if (!error) { resolve(true); } //no need to call the reject here, as it will have been called in the //'error' stream; }); }); }); }
De cette façon, vous pouvez appeler downloadFile()
, appeler then()
sur la promesse retournée et vous assurer que le fichier téléchargé aura terminé le traitement.
Ceci est correct et résout exactement le problème lié à l'erreur de données partielle
cela devrait être la réponse acceptée. il a corrigé l'erreur de téléchargement partiel
J'ai publié une approche plus propre sur le même concept d'utilisation de pipelines de flux ci-dessous: stackoverflow.com/a/64925465/3476378 .
import download from "downloadjs"; export const downloadFile = async (fileName) => { axios({ method: "get", url: `/api/v1/users/resume/${fileName}`, responseType: "blob", }).then(function (response) { download(response.data, fileName); }); }; it's work fine to me
Le problème avec un fichier cassé est dû à la contre- pression dans les flux de nœuds . Vous pouvez trouver ce lien utile à lire: https://nodejs.org/es/docs/guides/backpressuring-in-streams/
Je ne suis pas vraiment fan de l'utilisation des objets déclaratifs de base Promise dans les codes JS car je pense que cela pollue la logique de base réelle et rend le code difficile à lire. En plus de cela, vous devez provisionner des gestionnaires d'événements et des écouteurs pour vous assurer que le code est terminé.
Une approche plus propre sur la même logique que celle proposée par la réponse acceptée est donnée ci-dessous. Il utilise les concepts de pipelines de flux .
const util = require("util"); const stream = require("stream"); const pipeline = util.promisify(stream.pipeline); const downloadFile = async () => { try { await pipeline( axios.get('https://xxx/my.pdf', {responseType: 'blob'}), fs.createWriteStream("/temp/my.pdf")); console.log("donwload pdf pipeline successfull"); } catch (error) { console.error("donwload pdf pipeline failed", error); } } exports.downloadFile = downloadFile
J'espère que vous trouvez ça utile.
vous obtenez le journal de la console "Le fichier a été enregistré" et le fichier est créé et juste le contenu est faux?
où vous appelez axios.get? il n'attendra pas que le fichier soit écrit. mieux vaut promettre le fs ou utiliser fs-extra ou utiliser les méthodes promises de fs. et utilisez comme return fs.writeFile (...)
@RolandStarke oui, le fichier est enregistré
J'ai publié une approche plus propre pour résoudre le problème à l'aide de pipelines de flux de nœuds ci-dessous. C'est sur le même concept que propose la réponse acceptée. stackoverflow.com/a/64925465/3476378