2012-06-08 2 views
0

파일 업로드를 허용하는 Yesod 애플리케이션이 있습니다 (그러나 이보다 더 일반적인 질문입니다). 나는 또한 파일 dowloads을 허용합니다. 사용자가 단일 링크로 여러 파일을 다운로드 할 수있게하고 싶습니다. 이 질문에 따라 : How to download multiple files with one HTTP request? 유일한 해결책은 내부에있는 모든 파일로 파일 아카이브를 만드는 것 같습니다.웹 서버에서 즉시 작성되는 스트리밍 파일 아카이브

디스크에 쓰거나 외부 프로그램을 실행하지 않고 Haskage의 라이브러리를 사용하여 Haskell의 상수 메모리에서이 작업을 수행하려고합니다. 특히

다음은 비 - 솔루션 : 파일을 디스크 또는 일부 원격 URL을 통해 액세스에 대한 몇 가지 데이터베이스에있을 수 있습니다 : 아카이브를 생성하는 외부 프로그램을 호출

  • . 파일 시스템은 "읽기 전용"일 수 있습니다. 보안상의 이유로 외부 프로그램을 실행할 수 없습니다. 외부 프로그램이 배포를 복잡하게 만듭니다.

  • 소스 파일에서 디스크에 임시 아카이브 만들기 : 위의 "읽기 전용"파일 시스템을 참조하십시오. 또한 매우 비효율적입니다. 실제로 디스크에 쓰는 것은 실제로 느립니다.

  • 메모리에 전체 보관 파일을 만들고 이후에 제공 : 파일이 상당히 클 수 있습니다 (CD 이미지로 생각할 수 있음). 필요한 메모리가 너무 많습니다. 그것은 매우 의존

+0

메모리 내에서 10 명의 사용자가 5x 100MB 파일을 각각 다운로드하는 경우 보관 용으로 5GB 이상의 RAM이 필요합니다. 특히 확장 성이 좋지 않습니다. – Polynomial

+2

@Polynomial, 질문을 읽으면 @Tener가 명시 적으로 전체 아카이브를 메모리에 보관하고 싶지 않습니다. 즉석에서 내용을 압축하고 스트리밍 할 수있는'gzip'과'zip' 구현물이 많이 있습니다. – dflemstr

+0

@dflemstr 질문의 마지막 부분을 놓쳤습니다. 그래도 적당한 부하라도 서버의 CPU를 몰살시키는 것처럼 보입니다. – Polynomial

답변

1

는 파일을 지원하려는 형식에 (.ZIP, .tar.gz를, 가장 일반적인이 tar.bz2 있습니다),하지만 당신은 아카이브를 .ZIP 만들 수 zip-archive 라이브러리를 사용할 수 있습니다. 이러한 아카이브는 지연 바이트 문자열로 생성되므로 즉석에서 생성됩니다. 유일한 까다로운 부분은 올바른 내용으로 Archive 유형의 값을 생성하는 것입니다. 그것은 예를 들면 다음과 같습니다 데이터베이스 나 뭔가 압축 할 파일 시스템의 파일, 대신에 파일이없는 경우에, 당신은 수동으로 입력 Entry의 값을 구축 할 수 있습니다

import Codec.Archive.Zip 

-- ... and in your code: 
let archiveTemplate = 
    Archive 
    { zComment = ByteString.pack "Downloaded from mysite.com" 
    , zSignature = Nothing 
    , zEntries = [] 
    } 

let filesIWantToInclude = ["foo.png", "bar.iso"] 
entries <- forM filesIWantToInclude $ readEntry [] 
let archive = foldr addEntryToArchive archiveTemplate entries 

let byteString = fromArchive archive 
-- Now you can send the byteString over the network, or something. 

올바른 필드가 채워집니다. 압축하려는 데이터를 나타내는 게으름 뱅이 ByteString 만 있으면됩니다. toEntry 함수를 사용하여 항목을 생성 할 수 있습니다. eRelativePath 필드가 Entry 인 것은 파일 시스템의 실제 상대 경로가 아닌 .zip 아카이브 내부의 파일의 상대 경로입니다.

+0

나는이 도서관을 보았다. 언뜻보기에 그것은 비협조적인 것으로 보인다. 나는 그것을 테스트하지는 않았지만 소스 readEntry에서 보면 똑똑한 시도를하고 필요한 경우 압축 만하는 toEntry를 사용합니다. 테스트는 전체 파일을 압축하여 도움이되는지 확인하여 이루어집니다. 나는 이것이 전체 파일을 메모리에 저장하게하고 따라서 전체 라이브러리가 너무 많은 메모리를 소비 할 것이라고 생각한다. 수동으로 항목을 만들 수도 있습니다.비록 crc32 계산을위한 코드가 필요합니다. – Tener

+0

내부 압축 방법을 복사하여 크기 비교를 생략 할 수 있습니다 ... – dflemstr

관련 문제