카테고리 보관물: Javascript

Javascript

Node.js로 파일을 다운로드하는 방법 (타사 라이브러리를 사용하지 않고)? 필요하지 않습니다. 주어진 URL에서

타사 라이브러리를 사용하지 않고 Node.js로 파일을 어떻게 다운로드 합니까?

나는 특별한 것이 필요하지 않습니다. 주어진 URL에서 파일을 다운로드 한 다음 주어진 디렉토리에 저장하고 싶습니다.



답변

HTTP GET요청을 작성하여 response쓰기 가능한 파일 스트림으로 파이프 할 수 있습니다 .

const http = require('http');
const fs = require('fs');

const file = fs.createWriteStream("file.jpg");
const request = http.get("http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg", function(response) {
  response.pipe(file);
});

대상 파일이나 디렉토리 또는 URL 지정과 같이 명령 행에서 정보 수집을 지원하려면 Commander 와 같은 것을 확인하십시오 .


답변

오류를 처리하는 것을 잊지 마십시오! 다음 코드는 Augusto Roman의 답변을 기반으로합니다.

var http = require('http');
var fs = require('fs');

var download = function(url, dest, cb) {
  var file = fs.createWriteStream(dest);
  var request = http.get(url, function(response) {
    response.pipe(file);
    file.on('finish', function() {
      file.close(cb);  // close() is async, call cb after close completes.
    });
  }).on('error', function(err) { // Handle errors
    fs.unlink(dest); // Delete the file async. (But we don't check the result)
    if (cb) cb(err.message);
  });
};

답변

Michelle Tilley가 말했듯이 적절한 제어 흐름이 있습니다.

var http = require('http');
var fs = require('fs');

var download = function(url, dest, cb) {
  var file = fs.createWriteStream(dest);
  http.get(url, function(response) {
    response.pipe(file);
    file.on('finish', function() {
      file.close(cb);
    });
  });
}

finish이벤트를 기다리지 않고 순진 스크립트는 불완전한 파일로 끝날 수 있습니다.

편집 : @Augusto Roman에게 명시 적으로 호출되지 않고에 cb전달해야한다고 지적 해 주셔서 감사합니다 file.close.


답변

오류 처리와 관련하여 오류를 요청하는 것이 더 좋습니다. 응답 코드를 확인하여 유효성을 검사합니다. 여기서는 200 응답 코드에 대해서만 성공한 것으로 간주되지만 다른 코드는 좋습니다.

const fs = require('fs');
const http = require('http');

const download = (url, dest, cb) => {
    const file = fs.createWriteStream(dest);

    const request = http.get(url, (response) => {
        // check if response is success
        if (response.statusCode !== 200) {
            return cb('Response status was ' + response.statusCode);
        }

        response.pipe(file);
    });

    // close() is async, call cb after close completes
    file.on('finish', () => file.close(cb));

    // check for request error too
    request.on('error', (err) => {
        fs.unlink(dest);
        return cb(err.message);
    });

    file.on('error', (err) => { // Handle errors
        fs.unlink(dest); // Delete the file async. (But we don't check the result) 
        return cb(err.message);
    });
};

이 코드의 상대적 단순성에도 불구하고 요청 모듈 을 기본적으로 지원하지 않는 더 많은 프로토콜 (hello HTTPS!)을 처리 하므로 요청 모듈 을 사용하는 것이 http좋습니다.

그렇게 할 것입니다 :

const fs = require('fs');
const request = require('request');

const download = (url, dest, cb) => {
    const file = fs.createWriteStream(dest);
    const sendReq = request.get(url);

    // verify response code
    sendReq.on('response', (response) => {
        if (response.statusCode !== 200) {
            return cb('Response status was ' + response.statusCode);
        }

        sendReq.pipe(file);
    });

    // close() is async, call cb after close completes
    file.on('finish', () => file.close(cb));

    // check for request errors
    sendReq.on('error', (err) => {
        fs.unlink(dest);
        return cb(err.message);
    });

    file.on('error', (err) => { // Handle errors
        fs.unlink(dest); // Delete the file async. (But we don't check the result)
        return cb(err.message);
    });
};

답변

gfxmonk의 답변은 콜백과 file.close()완료 사이의 데이터 경쟁이 매우 엄격합니다 . file.close()실제로 닫기가 완료되면 호출되는 콜백을받습니다. 그렇지 않으면 파일을 즉시 사용하지 못할 수 있습니다 (매우 드물게!).

완전한 해결책은 다음과 같습니다.

var http = require('http');
var fs = require('fs');

var download = function(url, dest, cb) {
  var file = fs.createWriteStream(dest);
  var request = http.get(url, function(response) {
    response.pipe(file);
    file.on('finish', function() {
      file.close(cb);  // close() is async, call cb after close completes.
    });
  });
}

종료 이벤트를 기다리지 않고 순진 스크립트는 불완전한 파일로 끝날 수 있습니다. cb닫기를 통해 콜백을 예약하지 않으면 파일에 액세스하는 것과 실제로 준비중인 파일간에 경쟁이 발생할 수 있습니다.


답변

아마 node.js가 변경되었지만 다른 솔루션에 문제가있는 것 같습니다 (노드 v8.1.2 사용) :

  1. 당신은 호출 할 필요는 없습니다 file.close()에서 finish이벤트입니다. 기본적 fs.createWriteStream으로이 값은 autoClose로 설정되어 있습니다 : https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options
  2. file.close()오류가 발생하면 호출해야합니다. 파일을 삭제할 때 필요하지 않을 수도 unlink()있지만 ( ) 일반적으로 다음과 같습니다. https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
  3. 임시 파일은에 삭제되지 않습니다 statusCode !== 200
  4. fs.unlink() 콜백이 없으면 더 이상 사용되지 않습니다 (출력 경고)
  5. dest파일이 존재 하면 ; 재정의되었습니다

다음은 이러한 문제를 해결하는 수정 된 솔루션 (ES6 및 약속 사용)입니다.

const http = require("http");
const fs = require("fs");

function download(url, dest) {
    return new Promise((resolve, reject) => {
        const file = fs.createWriteStream(dest, { flags: "wx" });

        const request = http.get(url, response => {
            if (response.statusCode === 200) {
                response.pipe(file);
            } else {
                file.close();
                fs.unlink(dest, () => {}); // Delete temp file
                reject(`Server responded with ${response.statusCode}: ${response.statusMessage}`);
            }
        });

        request.on("error", err => {
            file.close();
            fs.unlink(dest, () => {}); // Delete temp file
            reject(err.message);
        });

        file.on("finish", () => {
            resolve();
        });

        file.on("error", err => {
            file.close();

            if (err.code === "EEXIST") {
                reject("File already exists");
            } else {
                fs.unlink(dest, () => {}); // Delete temp file
                reject(err.message);
            }
        });
    });
}

답변

시간 초과가있는 솔루션, 메모리 누수 방지 :

다음 코드는 Brandon Tilley의 답변을 기반으로합니다.

var http = require('http'),
    fs = require('fs');

var request = http.get("http://example12345.com/yourfile.html", function(response) {
    if (response.statusCode === 200) {
        var file = fs.createWriteStream("copy.html");
        response.pipe(file);
    }
    // Add timeout.
    request.setTimeout(12000, function () {
        request.abort();
    });
});

오류가 발생했을 때 파일을 만들지 말고 X 초 후에 시간 초과를 사용하여 요청을 닫는 것을 선호합니다.