2011-01-04 2 views
64

나는 Node.js를에 대한 일 처리하고있어 파일을 읽고 나는 그것이 존재 함을 설립했고 writeHead에 적절한 MIME 타입을 전송 한 후, 와이어를 내려 보내는 두 가지 방법을 발견했다 :node.js의 fs.createReadStream 대 fs.readFile의 장단점은 무엇입니까?

// read the entire file into memory and then spit it out 

fs.readFile(filename, function(err, data){ 
    if (err) throw err; 
    response.write(data, 'utf8'); 
    response.end(); 
}); 

// read and pass the file as a stream of chunks 

fs.createReadStream(filename, { 
    'flags': 'r', 
    'encoding': 'binary', 
    'mode': 0666, 
    'bufferSize': 4 * 1024 
}).addListener("data", function(chunk) { 
    response.write(chunk, 'binary'); 
}).addListener("close",function() { 
    response.end(); 
}); 

문제가되는 파일이 비디오처럼 크다면 fs.createReadStream이 더 나은 사용자 환경을 제공한다고 가정하면 정확합니까? 블록화가 덜한 것처럼 느껴집니다. 이게 사실인가요? 다른 프로, 단점, 경고 또는 내가 알아야 할 잡화가 있습니까?

답변

54

더 나은 방법, 당신은 단지 "데이터를"후크하려고하는 경우에 "쓰기()"와 "가까운"에서 "끝()"

// 0.3.x style 
fs.createReadStream(filename, { 
    'bufferSize': 4 * 1024 
}).pipe(response) 

// 0.2.x style 
sys.pump(fs.createReadStream(filename, { 
    'bufferSize': 4 * 1024 
}), response) 

read.pipe(write) 또는 sys.pump(read, write) 방법은있다 또한 흐름 제어를 추가하는 이점이 있습니다. 따라서 쓰기 스트림이 데이터를 신속하게 받아 들일 수없는 경우 메모리에서 버퍼링되는 데이터의 양을 최소화하기 위해 읽기 스트림이 중단되도록 지시합니다.

flags:"r"mode:0666은 FileReadStream이라는 사실을 암시합니다. binary enconding은 더 이상 사용되지 않습니다. 인코딩을 지정하지 않으면 원시 데이터 버퍼로만 작동합니다.

또한, 당신은 훨씬 야바위꾼를 제공하여 파일을 만들 수 있습니다 다른 케이크 추가 할 수 있습니다 req.headers.range에 대한

  1. 냄새 맡음을하고 /bytes=([0-9]+)-([0-9]+)/ 같은 문자열과 일치하는 경우를 참조하십시오. 그렇다면 처음부터 끝까지 스트림을 보내려는 것입니다. (누락 된 숫자는 0 또는 "끝"을 의미합니다.)
  2. stat() 호출에서 inode 및 생성 시간을 ETag 헤더로 해쉬합니다. 해당 헤더와 일치하는 "일치하지 않는"일치 요청 헤더를 얻으면 304 Not Modified을 다시 보내십시오.
  3. if-modified-since 헤더를 stat 오브젝트의 mtime 날짜와 대조하십시오. 제공된 날짜 이후에 수정되지 않은 경우 304

또한 일반적으로 가능한 경우 Content-Length 헤더를 보냅니다. (파일을 작성 했으므로이 파일을 가지고 있어야합니다.)

+0

굉장합니다, 고마워요! –

+0

+1 매우 유익합니다. 감사. – styfle

+0

@isaacs, 세 단계를 구현하는 방법에 대한 예를 제공해 주시겠습니까? 감사합니다. –

32

fs.readFile은 지적한대로 전체 파일을 메모리에로드하며, fs.createReadStream은 지정한 크기의 청크로 파일을 읽습니다.

클라이언트는 fs.createReadStream을 사용하여 데이터를 더 빨리 수신하기 시작합니다. fs.readFile은 전체 파일을 읽은 다음 클라이언트로 보내기 시작합니다. 이것은 무시해도 좋지만 파일이 매우 크고 디스크가 느린 경우 차이가 발생할 수 있습니다.

이 두 가지 기능을 100MB 파일에서 실행하면 첫 번째 파일은 100MB 메모리를 사용하여 파일을로드하고 후자는 최대 4KB 만 사용합니다.

편집 : 나는 큰 파일을 열 것이라고 말했기 때문에 특히 fs.readFile을 사용해야하는 이유가 표시되지 않습니다.

+0

에 인 Samer 부나 노드 코스에서 가져옵니다? – Elemento0

0

또 다른 것으로, 잘 알려지지 않은 점은 fs.readFilefs.createReadStream을 비교했을 때 Node가 비 사용 메모리를 정리하는 것이 더 낫다고 생각한다는 것입니다.어떤 것이 가장 효과적인지 확인하기 위해 이것을 테스트해야합니다. 또한 노드의 모든 새 버전에서이 기능이 향상되었습니다 (예 : 이러한 유형의 상황에서는 가비지 수집기가 더 스마트 해졌습니다).

1

큰 파일 인 경우 "readFile"은 메모리의 모든 파일 내용을 버퍼링하고 시스템을 정지시킬 수 있으므로 메모리를 망가뜨릴 수 있습니다. ReadStream은 청크로 읽습니다.

이 코드를 실행하고 작업 관리자의 성능 탭에서 메모리 사용을 관찰하십시오.

var fs = require('fs'); 

const file = fs.createWriteStream('./big_file'); 


for(let i=0; i<= 1000000000; i++) { 
    file.write('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n'); 
} 

file.end(); 


//.............. 
fs.readFile('./big_file', (err, data) => { 
    if (err) throw err; 
    console.log("done !!"); 
}); 

사실상 "완료!" 메시지. "readFile"은 버퍼가 파일 내용을 담을만큼 크지 않기 때문에 파일 내용을 읽을 수 없습니다.

이제 "readFile"대신 readStream 및 모니터 메모리 사용을 사용하십시오.

참고 : 코드와 함께`fs.readFile` 우리가 예를 당 진행을 잡을 못할 것을 의미 인 Pluralsight

관련 문제