>

저는 현재 Apache POI와 함께 Excel 파일을 만들고 있습니다. 멀티 파트 업로드 를 통해이 파일을 AWS S3로 보내려고합니다. . SXSSFWorkbook 을 BigGridDemo 는 문서 자체를 작성하고 시트 데이터를 전송합니다. 여기가 조금 까다로워집니다. 주로 작동하지만 NUL 로 인해 잘못된 Excel 파일을 생성하고 있습니다. 시트 데이터를 구성하는 XML 파일에 기록됩니다.

이 문제가 발생하는 이유를 추적하려고 할 때, 나는 이것을 우연히 발견했다 :

import java.io._
import java.util.zip._
val bo = new ByteArrayOutputStream()
val zo = new ZipOutputStream(bo)
zo.putNextEntry(new ZipEntry("1"))
zo.write("hello".getBytes())
zo.write("\nhello".getBytes())
val bytes1 = bo.toByteArray()
// bytes1: Array[Byte] = Array(80, 75, 3, 4, 20, 0, 8, 8, 8, 0, 107, -121, -9, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 49)
bo.reset()
zo.write("hello".getBytes())
val bytes2 = bo.toByteArray() // bytes2: Array[Byte] = Array()
zo.flush()
val bytes2 = bo.toByteArray() // bytes2: Array[Byte] = Array()
bo.size //res11: Int = 0
zo.putNextEntry() // If I make a new entry it works but I can't do this in real code...
bo.size // res17: Int = 66

기본 바이트 출력 스트림을 재설정하면 ZipOutputStream이 더 이상 아무것도 쓰지 않는 것으로 보입니다. 이것은 나를 놀라게 했으므로 ZipOutputStream의 기본 소스 코드 . 기본 방법은 DEFLATED이며 DeflaterOutputStream # write 다음, 압축 알고리즘에 더 깊은 스트림이 없어야한다는 것을 알 수없는 압축 알고리즘에 대해 생각했습니다. 재설정 또는 그 영향을받습니다. FULL_FLUSH 및 주목

The compression state is reset so that the inflater that works on the compressed output data can restart from this point if previous compressed data has been damaged or if random access is desired.

리셋 바이트 스트림이 아마도 손상된 데이터로 보일 수 있다고 상상할 수 있었기 때문에 나에게 좋은 소리를 냈다. 그래서 나는 최소한의 실험을 반복했다 :

import java.io._
import java.util.zip._
val bo = new ByteArrayOutputStream()
val zo = new ZipOutputStream(bo)
zo.setLevel(Deflater.FULL_FLUSH)
zo.putNextEntry(new ZipEntry("1"))
zo.write("hello".getBytes())
val bytes1 = bo.toByteArray()
// bytes1: Array[Byte] = Array(80, 75, 3, 4, 20, 0, 8, 8, 8, 0, 84, 75, -8, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 49)
zo.flush()
bo.reset()
zo.write("\nhello".getBytes())
zo.flush()
val bytes2 = bo.toByteArray() // bytes2: Array[Byte] = Array()

따라서 주사위가 없습니다. 내 목표는 모든 것을 메모리에 유지하고 (예 : 바이트 배열) 이미 UploadPartRequest에 쓴 바이트를 제거하여 메모리 압력을 낮추는 것이었지만, 실제로는 Excel 파일 형식은 사실상 zip 파일이므로 XML 파일은 압축해야합니다. 내 전체 코드는 분명히 조금 더 복잡하며 플레이 프레임 워크 및 Scala 2.12.6, 여기서 github에 넣고 추가 의견을 추가했습니다. 그것을 보거나 실행하십시오.

엑셀 파일을 디스크에 먼저 기록한 다음 업로드하여이 파일을 s3에 부분적으로 업로드 할 수 있다는 것을 알고 있습니다. 그러나 내 목적을 위해 모든 인 메모리 솔루션을 기대하고 있습니다. 대용량 임시 파일이 생성 될 때 웹 서버의 디스크 공간 문제를 처리합니다. 생성 된 행을 업로드 된 상태로 유지하면 업로드마다 메모리 압력이 일정하게 유지되어야한다고 생각했습니다. xml 파일 시트 데이터에서 현재 코드가 생성하는 내용은 다음과 같습니다.

...

나에게 바이트가 없다는 실험에도 불구하고 NUL이 결국 종료 된 이후로 더 많은 바이트가 발생하여 파일에 기록된다는 것을 알 수 있습니다.

그래서 ... 왜 이런 일이 발생합니까? 왜 ByteArrayOutputStream.reset()   ZipOutputStream 에 글을 쓰는 데 문제가있다 ? .reset ()을 호출하지 않으면 ByteArrayOutputStream 인 것 같습니다.  크기가 커질 때까지 확장되어 메모리 부족 오류가 발생합니까? 아니면 데이터가 압축되어 있기 때문에 걱정하지 않아도됩니까?

  • 답변 # 1

    나는 그것이 ByteArrayOutputStream.reset() 의 잘못이라고 생각하지 않습니다 .

    와이즈 비즈와 유사  다른 필터 스트림 CipherStreams  따라서 DeflaterOutputStream  기본 스트림에실제로쓰지 않습니다 ( ZipOutputStream )가 필요할 때까지 (때로 플러시 할 때도)

    나는이 경우 ByteArrayOutputStream 를 믿는다  특정 블록 크기 또는 ZipInputStream 를 닫을 때만 기본 스트림에 쓸 수 있습니다. ;확실하지는 않지만 제 추측입니다.

    예 :

    ZipEntry
    
    

    내가 val bo = new ByteArrayOutputStream() val zo = new ZipOutputStream(bo) zo.putNextEntry(new ZipEntry("example entry")) // v prints the entry header bytes v println(bo.toString()) zo.write("hello".getBytes()) zo.flush(); // v still only the entry header bytes v println(bo.toString()) 에서 알아 차린 한 가지  당신은 ExcelStreamingToS3Service - line 155 로 변경 할 수 있습니다 또는 이와 유사한 것. 전체 버퍼를 작성하는 것이 모든 zos.write(byteBuffer, offset, offset + bytesRead) 를 일으키는 원인이 될 수 있습니다.  읽기 중에 버퍼가 채워지지 않았고 여전히 많은 빈 인덱스가 있기 때문에 문자. 결국, XML은 NUL 이전에서 중단 된 곳에서 계속되는 것처럼 보입니다. 여기 같은 : NUL  모든 데이터를 작성하는 것처럼 보입니다 . <c r="C1 ... 940" t="inlineStr"> 와 함께 산재하십시오. s.

    NUL

  • 이전 sql - 마지막 달의 값만 선택
  • 다음 angular - JSON 데이터에서 채워진 드롭 다운