3

例を見つけたにもかかわらず、これに問題があります。エンコーディングの問題かもしれないと思いますが、よくわかりません。Cookieを使用するhttpsサーバーからファイルをプログラムでダウンロードしようとしています(したがって、httpwebrequestを使用しています)。ストリームの容量を確認するためにデバッグ出力していますが、出力 [生] ファイルは異なって見えます。他のエンコーディングを試してみましたが、役に立ちませんでした。

コード:

    Sub downloadzip(strURL As String, strDestDir As String)

    Dim request As HttpWebRequest
    Dim response As HttpWebResponse

    request = Net.HttpWebRequest.Create(strURL)
    request.UserAgent = strUserAgent
    request.Method = "GET"
    request.CookieContainer = cookieJar
    response = request.GetResponse()

    If response.ContentType = "application/zip" Then
        Debug.WriteLine("Is Zip")
    Else
        Debug.WriteLine("Is NOT Zip: is " + response.ContentType.ToString)
        Exit Sub
    End If

    Dim intLen As Int64 = response.ContentLength
    Debug.WriteLine("response length: " + intLen.ToString)

    Using srStreamRemote As StreamReader = New StreamReader(response.GetResponseStream(), Encoding.Default)
        'Using ms As New MemoryStream(intLen)
        Dim fullfile As String = srStreamRemote.ReadToEnd

        Dim memstream As MemoryStream = New MemoryStream(New UnicodeEncoding().GetBytes(fullfile))

        'test write out to flie
        Dim data As Byte() = memstream.ToArray()
        Using filestrm As FileStream = New FileStream("c:\temp\debug.zip", FileMode.Create)
            filestrm.Write(data, 0, data.Length)
        End Using

        Debug.WriteLine("Memstream capacity " + memstream.Capacity.ToString)
        'Dim strData As String = srStreamRemote.ReadToEnd
        memstream.Seek(0, 0)
        Dim buffer As Byte() = New Byte(2048) {}
        Using zip As New ZipInputStream(memstream)
            Debug.WriteLine("zip stream cap " + zip.Length.ToString)
            zip.Seek(0, 0)
            Dim e As ZipEntry

            Dim flag As Boolean = True
            Do While flag ' daft, but won't assign e=zip... tries to evaluate
                e = zip.GetNextEntry
                If IsNothing(e) Then
                    flag = False
                    Exit Do
                Else
                    e.UseUnicodeAsNecessary = True
                End If

                If Not e.IsDirectory Then
                    Debug.WriteLine("Writing out " + e.FileName)
                    '    e.Extract(strDestDir)

                    Using output As FileStream = File.Open(Path.Combine(strDestDir, e.FileName), _
                                                          FileMode.Create, FileAccess.ReadWrite)
                        Dim n As Integer
                        Do While (n = zip.Read(buffer, 0, buffer.Length) > 0)
                            output.Write(buffer, 0, n)
                        Loop
                    End Using

                End If
            Loop
        End Using
        'End Using
    End Using 'srStreamRemote.Close()
    response.Close()
End Sub

そのため、適切なサイズのファイルをダウンロードしましたが、dotnetzip はそれを認識せず、コピーされたファイルは不完全または無効な zip です。私は今日のほとんどをこれに費やしてきましたが、あきらめる準備ができています。

4

3 に答える 3

4

答えは問題を分解し、おそらくコードのいくつかの側面を変更することだと思います。

たとえば、応答ストリームを文字列に変換することをやめましょう:

Dim memStream As MemoryStream
Using rdr As System.IO.Stream = response.GetResponseStream
    Dim count = Convert.ToInt32(response.ContentLength)
    Dim buffer = New Byte(count) {}
    Dim bytesRead As Integer
    Do
        bytesRead += rdr.Read(buffer, bytesRead, count - bytesRead)
    Loop Until bytesRead = count
    rdr.Close()
    memStream = New MemoryStream(buffer)
End Using

次に、メモリ ストリームの内容をファイルに出力する簡単な方法があります。あなたのコードを検討してください

Dim data As Byte() = memstream.ToArray()
Using filestrm As FileStream = New FileStream("c:\temp\debug.zip", FileMode.Create)
    filestrm.Write(data, 0, data.Length)
End Using

で置き換えることができます

Using filestrm As FileStream = New FileStream("c:\temp\debug.zip", FileMode.Create)
    memstream.WriteTo(filestrm)
End Using

これにより、メモリ ストリームを別のバイト配列に転送してから、バイト配列をストリームにプッシュする必要がなくなります。実際には、メモリ ストリームは (ファイルストリームを介して) データをファイルに直接転送し、仲介者バッファーを節約できます。

あなたが使用している Zip/圧縮ライブラリを使用していないことは認めますが、上記の修正により、ストリーム、バイト配列、文字列などの間の不要な転送が削除され、発生していたエンコードの問題が解消されたことを願っています。

それを試してみて、どうやってうまくいくか教えてください。保存したファイル (「C:\temp\debug.zip」) を開いて、破損していないかどうかを確認してください。そうでない場合は、少なくともコード内のそれまでは問題なく動作していることがわかります。

于 2011-07-07T15:50:10.207 に答える
2

私は自分の完全な実用的な解決策を自分の質問に投稿すると思いました.2つの優れた回答を組み合わせています.ありがとう.

Sub downloadzip(strURL As String, strDestDir As String)
    Try

        Dim request As HttpWebRequest
        Dim response As HttpWebResponse

        request = Net.HttpWebRequest.Create(strURL)
        request.UserAgent = strUserAgent
        request.Method = "GET"
        request.CookieContainer = cookieJar
        response = request.GetResponse()

        If response.ContentType = "application/zip" Then
            Debug.WriteLine("Is Zip")
        Else
            Debug.WriteLine("Is NOT Zip: is " + response.ContentType.ToString)
            Exit Sub
        End If

        Dim intLen As Int32 = response.ContentLength
        Debug.WriteLine("response length: " + intLen.ToString)

        Dim memStream As MemoryStream
        Using stmResponse As IO.Stream = response.GetResponseStream()
            'Using ms As New MemoryStream(intLen)

            Dim buffer = New Byte(intLen) {}
            'Dim memstream As MemoryStream = New MemoryStream(buffer)

            Dim bytesRead As Integer
            Do
                bytesRead += stmResponse.Read(buffer, bytesRead, intLen - bytesRead)
            Loop Until bytesRead = intLen

            memStream = New MemoryStream(buffer)

            Dim res As Boolean = False
            res = ZipExtracttoFile(memStream, strDestDir)

        End Using 'srStreamRemote.Close()
        response.Close()



    Catch ex As Exception
        'to do :)
    End Try
End Sub


Function ZipExtracttoFile(strm As MemoryStream, strDestDir As String) As Boolean

    Try
        Using zip As ZipFile = ZipFile.Read(strm)
            For Each e As ZipEntry In zip

                e.Extract(strDestDir)

            Next
        End Using
    Catch ex As Exception
        Return False
    End Try

    Return True

End Function
于 2011-07-15T10:55:11.277 に答える
1

MemoryStream にダウンロードして、それを調べることができます。

Public Sub Download(url as String)
    Dim req As HttpWebRequest = System.Net.WebRequest.Create(url)
    req.Method = "GET"
    Dim resp As HttpWebResponse = req.GetResponse()
    If resp.ContentType = "application/zip" Then
        Console.Error.Write("The result is a zip file.")
        Dim length As Int64 = resp.ContentLength
        If length = -1 Then
            Console.Error.WriteLine("... length unspecified")
            length = 16 * 1024
        Else
            Console.Error.WriteLine("... has length {0}", length)
        End If
        Dim ms As New MemoryStream
        CopyStream(resp.GetResponseStream(), ms)  '' **see note below!!!!
        '' list contents of the zip file
        ms.Seek(0,SeekOrigin.Begin)
        Using zip As ZipFile = ZipFile.Read (ms)
            Dim e As ZipEntry
            Console.Error.WriteLine("Entries:")
            Console.Error.WriteLine("  {0,22}  {1,10}  {2,12}", _
                                    "Name", "compressed", "uncompressed")
            Console.Error.WriteLine("----------------------------------------------------")
            For Each e In zip
                Console.Error.WriteLine("  {0,22}  {1,10}  {2,12}", _
                                        e.FileName, _
                                        e.CompressedSize, _
                                        e.UncompressedSize)
            Next
        End Using
    Else
        Console.Error.WriteLine("The result is Not a zip file.")
        CopyStream(resp.GetResponseStream(), Console.OpenStandardOutput)
    End If
End Sub


Private Shared Sub CopyStream(input As Stream, output As Stream)
    Dim buffer(32768 - 1) As Byte
    Dim n As Int32
    Do
        n = input.Read(buffer, 0, buffer.Length)
        If n = 0 Then Exit Do
            output.Write(buffer, 0, n)
    Loop
End Sub

編集

1 つだけ注意してください - Zip ファイルが非常に大きい場合、このコード (このアプローチ) を使用することはお勧めしません。「非常に大きい」とはどのくらいの大きさですか? もちろん、それは状況によります。上記で提案したコードは、ファイルをメモリ ストリームにダウンロードします。これは、もちろん、zip ファイルの内容全体がメモリに保持されることを意味します。28kbのzipファイルであれば問題ありません。しかし、それが 2GB の zip ファイルである場合、大きな問題が発生する可能性があります。

その場合、MemoryStream ではなく、ディスク上の一時ファイルにストリーミングする必要があります。それは読者の演習として残しておきます。

上記は、「妥当なサイズ」の zip ファイルで機能します。「妥当な」は、マシンの構成とアプリケーションのシナリオによって異なります。

于 2011-07-13T17:38:41.977 に答える