2016-12-13 17 views
8

के माध्यम से सामग्री उत्पन्न करने के लिए अक्का HTTP का उपयोग कैसे करें मैं अक्का स्ट्रीम और अक्का HTTP के लिए काफी नौसिखिया हूं।आउटपुट स्ट्रीम

मैं एक साधारण HTTP सर्वर जेनरेट करना चाहता हूं जो किसी फ़ोल्डर की सामग्री से ज़िप फ़ाइल उत्पन्न कर सकता है और उसे क्लाइंट को भेज सकता है।

org.zeroturnaround.zip.ZipUtil एक ज़िप फ़ाइल को बहुत आसान बनाने का कार्य बनाता है, लेकिन इसे outputStream की आवश्यकता है।

यहाँ मेरी समाधान (स्काला भाषा में लिखा गया है):

  val os = new ByteArrayOutputStream() 
      ZipUtil.pack(myFolder, os) 
      HttpResponse(entity = HttpEntity(
       MediaTypes.`application/zip`, 
       os.toByteArray)) 

यह समाधान काम करता है, लेकिन याद करने के लिए सभी सामग्री को रहता है, तो यह स्केलेबल नहीं है।

मुझे लगता है कि इस को हल करने के लिए महत्वपूर्ण इस का उपयोग करने के लिए है:

val source = StreamConverters.asOutputStream() 

लेकिन यह कैसे उपयोग करने के लिए पता नहीं है। :-(

किसी भी मदद

कृपया?

उत्तर

3

मैं एक ही समस्या थी। आदेश में यह backpressure संगत मैं कृत्रिम InputStream जो बाद में StreamConverters.fromInputStream(() => input) के माध्यम से Source में बदल जाती है जो बदले में आप अपने अक्का से लौटने लिखना पड़ा बनाने के लिए -http डीएसएल complete निर्देश।

यहाँ मैं क्या लिखा है।

import java.io.{File, IOException, InputStream} 
import java.nio.charset.StandardCharsets 
import java.time.LocalDate 
import java.time.format.DateTimeFormatter 

import org.apache.commons.compress.archivers.sevenz.{SevenZArchiveEntry, SevenZFile} 

import scala.annotation.tailrec 
import scala.util.{Failure, Success, Try} 

class DownloadStatsZipReader(path: String, password: String) extends InputStream { 

    private val (archive, targetDate) = { 
    val inputFile = new SevenZFile(new File(path), password.getBytes(StandardCharsets.UTF_16LE.displayName())) 

    @tailrec 
    def findValidEntry(): Option[(LocalDate, SevenZArchiveEntry)] = 
     Option(inputFile.getNextEntry) match { 
     case Some(entry) => 
      if (!entry.isDirectory) { 
      val parts = entry.getName.toLowerCase.split("\\.(?=[^\\.]+$)") 
      if (parts(1) == "tab" && entry.getSize > 0) 
       Try(LocalDate.parse(parts(0), DateTimeFormatter.ISO_LOCAL_DATE)) match { 
       case Success(localDate) => 
        Some(localDate -> entry) 
       case Failure(_) => 
        findValidEntry() 
       } 
      else 
       findValidEntry() 
      } else 
      findValidEntry() 
     case None => None 
     } 

    val (date, _) = findValidEntry().getOrElse { 
     throw new RuntimeException(s"$path has no files named as `YYYY-MM-DD.tab`") 
    } 
    inputFile -> date 
    } 

    private val buffer = new Array[Byte](1024) 
    private var offsetBuffer: Int = 0 
    private var sizeBuffer: Int = 0 

    def getTargetDate: LocalDate = targetDate 

    override def read(): Int = 
    sizeBuffer match { 
     case -1 => 
     -1 
     case 0 => 
     loadNextChunk() 
     read() 
     case _ => 
     if (offsetBuffer < sizeBuffer) { 
      val result = buffer(offsetBuffer) 
      offsetBuffer += 1 
      result 
     } else { 
      sizeBuffer = 0 
      read() 
     } 
    } 

    @throws[IOException] 
    override def close(): Unit = { 
    archive.close() 
    } 

    private def loadNextChunk(): Unit = try { 
    val bytesRead = archive.read(buffer) 
    if (bytesRead >= 0) { 
     offsetBuffer = 0 
     sizeBuffer = bytesRead 
    } else { 
     offsetBuffer = -1 
     sizeBuffer = -1 
    } 
    } catch { 
    case ex: Throwable => 
     ex.printStackTrace() 
     throw ex 
    } 
} 

यदि आप पाते हैं मेरी कोड में कीड़े तो कृपया मुझे बताएं।

9

इस

val byteSource: Source[ByteString, Unit] = StreamConverters.asOutputStream() 
    .mapMaterializedValue(os => ZipUtil.pack(myFolder, os)) 
HttpResponse(entity = HttpEntity(
      MediaTypes.`application/zip`, 
      byteSource)) 

प्रयास करें आप केवल OutputStream एक बार स्रोत materialized हो जाता है, जो तत्काल नहीं हो सकता है के लिए पहुँच जाते हैं। सिद्धांत रूप में स्रोत कई बार भौतिक हो सकता है, इसलिए आपको इससे निपटने में सक्षम होना चाहिए।

+2

मैं मैं लिख इस खुद भी काफी शिक्षाप्रद और मजेदार था ... – expert

+1

यह जानता था चाहते हैं, लेकिन यह मेरे मामले में विफल रहता है: 'java.lang.IllegalStateException: अभी तक प्रारंभ नहीं किया गया: केवल setHandler GraphStageLogic कन्स्ट्रक्टर ' –

+0

यह आसान की तरह लग रहा से पहले :) –

संबंधित मुद्दे