2012-08-07 2 views
2

아무도 다음 코드가 작동하지 않는 이유를 말해 줄 수 있습니까? Zip 스트림 용으로 SharpZipLib API를 사용하고 있으며, 현재 사이트에서 최신 버전 인 DL을 다운로드했습니다. 디스크에 입출력을 수행 할 필요없이 한 zip 파일의 내용을 다른 zip 파일로 병합하려면이 논리를 사용하십시오. 의도 한 zip 파일에는 Windows 용 예약 파일 이름이 들어있을 수 있습니다. 여러 개의 다른 원본 및 대상 zip 파일 (예약 된 이름과 그 포함되지 않은 파일)을 시도했습니다. 코드는 예외를 발생시키지 않으며 각 쓰기 작업 전에 버퍼를 검사하면 실제 데이터가 포함되어 있음을 알 수 있지만 전체 작업이 완료된 후 대상 zip 파일의 크기는 변경되지 않고 탐색 할 수 있습니다 새로운 파일 (코드가 추가하는 파일)이 실제로 대상 파일에 추가되지 않았는지 확인합니다. 내가 볼 :(다른 Zip 파일로 압축을 풉니 다

public static void CopyToZip(string inArchive, string outArchive) 
    { 

     ZipOutputStream outStream = null; 
     ZipInputStream inStream = null; 
     try 
     { 
      outStream = new ZipOutputStream(File.OpenWrite(outArchive)); 
      outStream.IsStreamOwner = false; 
      inStream = new ZipInputStream(File.OpenRead(inArchive)); 
      ZipEntry currentEntry = inStream.GetNextEntry(); 
      while (currentEntry != null) 
      { 

       byte[] buffer = new byte[1024]; 
       ZipEntry newEntry = new ZipEntry(currentEntry.Name); 
       newEntry.Size = currentEntry.Size; 
       newEntry.DateTime = currentEntry.DateTime; 
       outStream.PutNextEntry(newEntry); 
       int size = 0; 
       while ((size = inStream.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        outStream.Write(buffer, 0, size); 
       } 
       outStream.CloseEntry(); 

       currentEntry = inStream.GetNextEntry(); 
      } 
      outStream.IsStreamOwner = true; 
     } 
     catch (Exception e) 
     { 
      throw e; 
     } 
     finally 
     { 
      try { outStream.Close(); } 
      catch (Exception ignore) { } 
      try { inStream.Close(); } 
      catch (Exception ignore) { } 
     }  
    } 

답변

0

한 가지 문제는 그것으로 새 항목을 병합보다 기존 출력 파일을 오히려 대체 할 File.OpenWrite()를 사용하여 출력 zip 파일을 여는 것입니다.이

SharpDevelop Wiki에서 메모리 스트림을 사용하여 zip 파일을 업데이트하는 예를 보여줍니다 : http://wiki.sharpdevelop.net/SharpZipLib_Updating.ashx#Updating_a_zip_file_in_memory_1

+0

여기 게시 한 코드를 작성하기 위해 예제를 따라했습니다. 위의 코드가 대상 zip 파일의 상태를 전혀 변경하지 않는 경우 덮어 쓰기 여부에 관계없이이 시점에서 중요하지 않습니다. 덮어 쓰는 경우, 적어도 디버깅 할 것이 있습니다 ... 나는 memeory 스트림을 사용할 필요가 없습니다. 내가 '디스크를 사용하지 않고'라는 말은 하드 드라이브에 하나의 압축 파일 내용을 추출 할 수 없다는 것입니다. 그런 다음 다른 압축 파일로 다시 압축합니다. Windows 파일 이름 지정 규칙 때문에 HD에서 압축을 풀지 않고도 한 우편 번호에서 다음 우편 번호로 이동해야합니다. –

+0

File.OpwnWrite()의 새 FileStream (outArchive, FileMode.Open)이 사용되었습니다. 그것은 결과를 전혀 변경하지 못했습니다. –

1

DotNet zip을 http://dotnetzip.codeplex.com/에서 작성했습니다. 다음은 구현 예입니다.

public static void CopyToZip(string inArchive, string outArchive, string tempPath) 
    { 
     ZipFile inZip = null; 
     ZipFile outZip = null; 

     try 
     { 
      inZip = new ZipFile(inArchive); 
      outZip = new ZipFile(outArchive); 
      List<string> tempNames = new List<string>(); 
      List<string> originalNames = new List<string>(); 
      int I = 0; 
      foreach (ZipEntry entry in inZip) 
      { 
       if (!entry.IsDirectory) 
       { 
        string tempName = Path.Combine(tempPath, "tmp.tmp"); 
        string oldName = entry.FileName; 
        byte[] buffer = new byte[4026]; 
        Stream inStream = null; 
        FileStream stream = null; 
        try 
        { 
         inStream = entry.OpenReader(); 
         stream = new FileStream(tempName, FileMode.Create, FileAccess.ReadWrite); 
         int size = 0; 
         while ((size = inStream.Read(buffer, 0, buffer.Length)) > 0) 
         { 
          stream.Write(buffer, 0, size); 
         } 
         inStream.Close(); 
         stream.Flush(); 
         stream.Close(); 
         inStream = new FileStream(tempName, FileMode.Open, FileAccess.Read); 

         outZip.AddEntry(oldName, inStream); 
         outZip.Save(); 
        } 
        catch (Exception exe) 
        { 
         throw exe; 
        } 
        finally 
        { 
         try { inStream.Close(); } 
         catch (Exception ignore) { } 
         try { stream.Close(); } 
         catch (Exception ignore) { } 
        } 
       } 
      } 

     } 
     catch (Exception e) 
     { 
      throw e; 
     } 
    } 
+0

주어진 디렉토리에서 임시 파일 (tmp.tmp)을 사용하여 파일 이름 문제를 해결 한 다음 해당 파일에 아카이브의 원래 이름을 지정합니다. –

+0

코드가 정상적으로 작동하지만 .. 몇개의 메모가 있습니다. . 1. 코드는 추가 된 각 항목에 대해 출력 파일을 한 번 저장합니다. 이것은 불필요합니다. 2. 파일 시스템 전체에 쓰는 것을 피할 수 있습니다. 자세한 내용은 내 대답을 참조하십시오. – Cheeso

+0

필자는 그곳에 저에게 전화를해야만했다. (필자의 테스트 동안, 내가 추가 할 파일 목록을 대기시키고, 어떤 이유로 든 Save() 메소드에 대한 한 번의 호출로 한번에 추가하려고 시도했을 때, 파일은 변경되지 않았습니다. 나는 내가하는 곳에서 저축 한 대폭적인 성과를 잘 알고 있지만 불행히도 나는 그것을 적절하게 작동시킬 수 없었다. –

0

다음은 입력 zip에서 읽고 출력 zip에 쓸 수있는 간단한 코드입니다 (잠재적으로 이미 존재할 수 있음). 임시 데이터를 파일 시스템에 쓰지 않아도됩니다.

public static void CopyToZip(string inArchive, string outArchive) 
    { 
     using (inZip = new ZipFile(inArchive), 
      outZip = new ZipFile(outArchive)) 
     { 
      Func<String,Func<String,Stream>> getInStreamReturner = (name) => { 
       return new Func<String,Stream>(a){ return inZip[a].OpenReader(); }; 
      }; 
      foreach (ZipEntry entry in inZip) 
      { 
       if (!entry.IsDirectory) 
       { 
        string zipEntryName = entry.FileName; 
        outZip.AddEntry(zipEntryName, 
            getInStreamReturner(zipEntryName), 
            (name, stream) => stream.Close()); 
       } 
      } 
      outZip.Save(); 
     } 
    } 

주 : 오프너와 가까이 :

  1. 이 방법이 위임을 허용 ZipFile.AddEntry 오버로드를 사용합니다. 이 함수는 ZipFile.Save의 시점에 이라고합니다. 이전 대리자는 압축 할 데이터가 포함 된 스트림을 열고 반환해야합니다. 후자는 스트림을 닫아야합니다.

  2. ZipFile.Save에 오른쪽 스트림을 열려면 getInStreamReturner Func을 정의해야합니다. zipEntryName은 매번 루프를 통해 값이 변경된다는 점에 유의하십시오. 또한 ZipEntry.OpenReader()은 실제 zip 데이터에 스트림을 엽니 다. 스트림은 읽거나 압축을 해제합니다. 한 번에 ZipFile 당 하나만 열 수 있습니다. getInStreamReturner은 루프를 통해 매번 새로운 함수를 생성하므로 의 값을 ZipFile.Save의 시간에 참조 용으로 유지하는 클로저를 만듭니다.

  3. inArchive와 outArchive간에 이름 충돌이 있으면이 방법이 실패합니다. 그것을 피하기 위해 그것을 확인하고 어떻게 든 피해야합니다. 새로운 고유 한 이름을 고안하거나 중복 된 이름의 항목을 outarchive에 추가하지 마십시오.

  4. 테스트하지 않았습니다.


    이 방법은 파일 시스템에 기록하지 않지만

, 그것은 압축 해제를 수행하고 파일 데이터를 다시 압축.압축 해제/재 압축 점프없이 항목을 마이그레이션하기 위해 DotNetZip에 기능을 제공하기위한 공개 요청이 있습니다. 나는 아직 그것을 구현하지 않았다.

관련 문제