2

元のオフィス ファイルは問題なく動作していますが (ワードとエクセルを試しました)、ファイルをバイナリとしてデータベースにアップロードし、そこから PC にダウンロードしてダウンロードしたファイルを開くと、「Excel が見つかりました」という警告メッセージが表示されます。コンテンツを読み取れません」などのエラーが発生し、元のファイルに比べてファイルがプレーンになっています。

正確なエラー メッセージは次のとおりです。「ファイル名.xls に読み取り不可能なコンテンツが見つかりました。このブックのコンテンツを復元しますか? このブックの発行元が信頼できる場合は、[はい] をクリックしてください。」

ファイルのアップロード方法:

'UPLOAD FILE
Dim fi As New FileInfo(FilePath)
Dim s As Stream = fi.OpenRead()
Dim buffer(fi.Length) As Byte 'I put the buffer in database in varbinary(max) format
s.Read(buffer, 0, fi.Length)
s.Close()

ファイルをダウンロードして開く方法:

'DOWNLOAD FILE
Dim fi As New FileInfo(FilePath)
Dim s As Stream = fi.OpenWrite()
Dim buffer As Byte() = reader("Binary")
s.Write(buffer, 0, buffer.Length)
s.Close()

'OPEN FILE
Dim p As New Process
p.StartInfo = New ProcessStartInfo(FilePath)
p.Start()

アップデート:

示唆されたように、私は単純にファイルをコピーして、SQL を完全に排除しようとしました。これも失敗した私が試したコードです:

Private Sub CopyFile(ByVal filePath As String)
    Dim fi As New FileInfo(filePath)
    Dim s As Stream = fi.OpenRead()
    Dim buffer(CType(fi.Length, Integer) - 1) As Byte
    s.Read(buffer, 0, CType(fi.Length, Integer))
    s.Close()

    Dim fi2 As New FileInfo(filePath & " Copy")
    Dim s2 As Stream = fi2.OpenWrite()
    s2.Write(buffer, 0, buffer.Length)
    s2.Close()
End Sub
4

1 に答える 1

3

この MSDN 記事で説明されているように、VB.NET 配列は、C# などの他の言語とは異なる方法で宣言されます。他の言語では、固定長配列を宣言するときに、指定されたサイズが配列の全長として使用されます。たとえば、C# では、ステートメントfixed byte buffer[3];は 3 つの要素 (インデックス 0 ~ 2) を含むバイト配列を宣言します。ただし、VB では、サイズではなく、固定配列を宣言するときに指定されたサイズが配列の上限として使用されます。したがって、VB では、ステートメントDim buffer(3) As Byteは 4 つの要素 (インデックス 0 ~ 3) を含むバイト配列を宣言します。

それを念頭に置いて、コードをよく見ると、実際にはファイルのサイズよりも 1 要素大きいバイト配列を宣言しています (インデックス 0 から fi.Length まで)。次に、インデックス 0 から始まるファイル全体をバイト配列に読み込みます。したがって、配列の最後のバイトは値 0 (ヌル文字) のままになります。次に、最後の null バイトを含め、バイト配列の内容全体を新しいファイルに書き出します。したがって、コードはファイル内のすべてのバイトを正しくコピーしていますが、ファイルの最後に余分な null バイトを追加しているため、Excel は満足できません。元のファイル サイズと新しく作成したファイルのサイズを見ると、新しいファイルが元のファイルより 1 バイト大きいことがわかります。

これを修正するには、ファイルとまったく同じ長さになるように、配列を宣言するときに配列のサイズを調整する必要があります。

Dim buffer(fi.Length - 1) As Byte

ただし、私はそれに取り組んでいますが、あなたが投稿したコードの他のいくつかの改善領域を指摘する義務があると感じています. まずIDisposable、 などのインターフェイスを実装するオブジェクトを使用する場合は、可能な限りステートメントStreamを使用することをお勧めします。Usingそうすることで、例外が発生した場合でも、オブジェクトが常に適切にクローズ/破棄されることが保証されます。たとえば、次のようにしたほうがよいでしょう。

Dim fi As New FileInfo(FilePath)
Using s As Stream = fi.OpenRead()
    Dim buffer(fi.Length - 1) As Byte
    s.Read(buffer, 0, fi.Length)
End Using

また、配列サイズまたはバッファ長の引数としてOption Strictfi.Length (a ) を使用することは許可されないため、使用していないことは明らかです。Longをオンにすると、値をOption Strictにキャストすることを明示的に指定する必要があります。例えば:LongInteger

Dim fi As New FileInfo(FilePath)
Using s As Stream = fi.OpenRead()
    Dim buffer(CInt(fi.Length) - 1) As Byte
    s.Read(buffer, 0, CInt(fi.Length))
End Using

オンにするOption Strictことは、ほとんどの状況で非常に良い考えです。変数の型と、いつデータが失われる可能性があるかを認識する必要があります。例えばこの場合、Option Strictオンにしたことで、ファイルサイズ( Long.MaxValue)が配列の最大長( )よりも大きくなる可能性があることに気付くInteger.MaxValueので、非常に大きなファイルを扱いたい場合は、ファイルをチャンクで読み書きするループを書く必要があります。大きなファイルを処理したくない場合でも、オーバーフロー例外がスローされるのを許可するのではなく、エラーを適切に処理できるように、最初にサイズを確認することをお勧めします。

If fi.Length >= Integer.Max Then
    'Display or log error that the file is too large, and skip loading the file
Else
    'Load file
End If

最後に、大きなファイルの処理を気にしない場合は、ファイル内のすべてのバイトを読み書きする簡単な方法があります。

'UPLOAD FILE
Dim buffer() As Byte = File.ReadAllBytes(filePath)

'DOWNLOAD FILE
Dim buffer As Byte() = reader("Binary")
File.WriteAllBytes(filePath, buffer)
于 2012-10-03T12:31:00.820 に答える