存储在SQL Server中的.docx导致“打开文件时出错”

时间:2013-11-11 01:02:04

标签: sql-server vb.net ms-word

我正在研究用VB.net 4.0编写的带有SQL Server 2005数据库的传统Windows桌面应用程序。 应用程序基于存储在数据库中的Word模板生成报告。 有一个管理部分允许将新的Word报告模板(.docx)加载到数据库中,以防报告中的文本发生某些更改。 管理表单允许添加新文件,或删除或更新现有文件。当添加一个新文件时,它会要求一个代码(文本)作为数据库查找表中文件的主键存储。它还允许从数据库中选择和打开文件,这样它就可以了被观看。

可以始终如一地重现以下行为: 可以使用新代码(主键)添加新的.docx文件。 该文件可以成功打开。 如果使用新的.docx更新任何现有文件,则任何打开的尝试都将失败,并在Word中显示错误消息“打开文件时出错”。 如果删除该文件的记录,并且使用新代码(PK)添加相同的文件,则可以成功打开。 如果使用与删除文件相同的代码(PK)添加相同的文件(或任何.docx文件),它将显示写入DB ok,但任何打开该文件的尝试都将失败,并显示与上述相同的错误消息

无法打开的.docx文件比可以成功打开的文件长一个字节。 无法通过Word打开的.docx文件仍然可以作为存档打开(例如7zip),文件内容看起来是相同的。

覆盖现有文件,或者将已删除文件的代码(PK)与任何其他文件类型(包括.doc)一起使用都可以正常工作。只有.docx文件会导致问题;这是一个遗憾,因为.docx文件是必需的,因为通过使用OpenXML代码操作Word文档内容来实现报告生成。

以下是将文件插入数据库的代码:

Private Sub btnInsert_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles     btnInsert.Click
    Dim sName As String = InputBox("What is the name of this Resource")
    If (sName.Length > 0) Then
        Dim ofd As New OpenFileDialog
        With ofd
            .CheckFileExists = True
            .ShowReadOnly = False
            .Filter = "All Files|*.*"
            If (.ShowDialog = DialogResult.OK) Then
                Dim fs As FileStream = New FileStream(.FileName, FileMode.Open, FileAccess.Read)
                Dim docByte As Byte() = New Byte(fs.Length - 1) {}
                fs.Read(docByte, 0, Convert.ToInt32(fs.Length))
                fs.Close()

                Dim FileType As String = Path.GetExtension(.FileName).ToLower

                Dim conn As New SqlConnection(strConnString)
                Dim cmd As New SqlCommand(sqlInsert, conn)
                cmd.Parameters.AddWithValue("@ID", sName)
                cmd.Parameters.AddWithValue("@Bytes", docByte)
                cmd.Parameters.AddWithValue("@Types", FileType)

                conn.Open()
                cmd.ExecuteNonQuery()
                conn.Close()

                MsgBox("Saved to DB")
                Dim li As ListViewItem = lvwResource.Items.Add(sName)
                li.SubItems.Add(FileType)

                docByte = Nothing
                fs.Dispose()
            End If
        End With
    End If
End Sub

检索的代码:

Private Sub btnOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpen.Click

    Dim sName As String = lvwResource.SelectedItems(0).Text
    Dim sType As String = lvwResource.SelectedItems(0).SubItems(1).Text
    Dim fileName As String = String.Format("{0}{1}{2}", Path.GetTempPath, sName, sType)

    Dim conn As New SqlConnection(strConnString)
    Dim cmd As New SqlCommand(sqlSelect, conn)
    cmd.Parameters.AddWithValue("@ID", sName)

    Dim da As New SqlDataAdapter(cmd)

    Dim dt As New DataTable
    da.Fill(dt)

    Dim docByte() As Byte = dt.Rows(0)(1)
    Dim fs As New FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)
    fs.Write(docByte, 0, Convert.ToInt32(docByte.Length))
    fs.Dispose()

    Try
        System.Diagnostics.Process.Start(fileName)
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.Question, "Unknown Resource Type")
    End Try
End Sub

更多细节:工作站是带有Microsoft Office 2003 SP3的Windows XP Sp3,服务器是Server 2003标准版SP2,db是SQL Server 2005 SP2。 这是一个庞大的组织,我对他们过时的软件没有影响力。

1 个答案:

答案 0 :(得分:0)

好的,找到了解决方案。 非常感谢Franklin Chan在MSDN论坛上的时间和耐心帮助我。

错误发生在更新代码中,我从未在此发布过(我的错!)。

当阅读要更新的文件和现有记录时,我有以下代码:

Dim fs As FileStream = New FileStream(.FileName, FileMode.Open)
Dim img As Byte() = New Byte(fs.Length) {}
fs.Read(img, 0, fs.Length)
fs.Close()

我在插入子中以正确的方式进行,有趣的是。正确的语法是:

Dim fs As FileStream = New FileStream(.FileName, FileMode.Open, FileAccess.Read)
Dim img As Byte() = New Byte(fs.Length - 1) {}
fs.Read(img, 0, Convert.ToInt32(fs.Length))
fs.Close()

缺少的另一个重要步骤是在从数据库中提取并打开之前清除临时文件,因此添加:

If System.IO.File.Exists(fileName) = True Then
    System.IO.File.Delete(fileName)
End If

到btnOpen()代码。