如何使用字节流形成Word文档

本文关键字:Word 文档 何使用 字节流 | 更新日期: 2023-09-27 18:05:26

我有一个字节流,实际上(如果正确)将形成一个有效的Word文件,我需要将此流转换为Word文件而不将其写入磁盘,我从SQL Server数据库表中获取原始流:

ID   Name    FileData
----------------------------------------
1    Word1   292jf2jf2ofm29fj29fj29fj29f2jf29efj29fj2f9 (actual file data)

FileData字段携带数据。

Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document doc = new Microsoft.Office.Interop.Word.Document(); 
doc = word.Documents.Open(@"C:'SampleText.doc");
doc.Activate();

上面的代码从文件系统打开并填充一个Word文件,我不想这样,我想定义一个新的Microsoft.Office.Interop.Word.Document,但是我想从字节流手动填充它的内容。

获得内存中的Word文档后,我想对关键字进行一些解析。

任何想法?

如何使用字节流形成Word文档

  1. 创建一个内存文件系统,有相应的驱动程序。
  2. 给word一个ftp服务器路径(或其他东西)的路径,然后使用它来推送数据。

需要注意的一点是:在数据库中存储文件通常不是一个好的设计。

你可以看看Sharepoint如何解决这个问题。他们为存储在数据库中的文档创建了一个web界面。

在你的应用程序中创建或嵌入一个可以向Word提供页面的web服务器并不难。您甚至不需要使用标准端口

可能没有任何直接的方法可以做到这一点。我找到了几个解决方案:

  • 使用OpenOffice SDK来操作文档而不是Word互操作
  • 将数据写入剪贴板,然后从剪贴板写入Word

我不知道这是否为你做了,但显然API不提供你所需要的(不幸的是)

实际上只有两种方法可以编程地打开Word文档——作为物理文件或作为流。有一个"包",但这并不真正适用。

流方法包括在这里:https://learn.microsoft.com/en-us/office/open-xml/how-to-open-a-word-processing-document-from-a-stream

但是即使它依赖于有一个物理文件来形成流:

string strDoc = @"C:'Users'Public'Public Documents'Word13.docx";
Stream stream = File.Open(strDoc, FileMode.Open);

我能提供的最佳解决方案是将文件写入一个临时位置,应用程序的服务帐户有权写入:

string newDocument = @"C:'temp'test.docx";
WriteFile(byteArray, newDocument);

如果它在我的例子中没有对"temp"文件夹的权限,你只需要添加你的应用程序的服务帐户(应用程序池,如果它是一个网站)来完全控制该文件夹。

您将使用以下WriteFile()函数:

/// <summary>
/// Write a byte[] to a new file at the location where you choose
/// </summary>
/// <param name="byteArray">byte[] that consists of file data</param>
/// <param name="newDocument">Path to where the new document will be written</param>
public static void WriteFile(byte[] byteArray, string newDocument)
{
    using (MemoryStream stream = new MemoryStream())
    {
        stream.Write(byteArray, 0, (int)byteArray.Length);
        // Save the file with the new name
        File.WriteAllBytes(newDocument, stream.ToArray());
    }
}
从那里,您可以使用OpenXML打开它并编辑文件。没有办法将byte[]形式的Word文档直接打开到Word实例(Interop, OpenXML或其他)中,因为您需要documentPath,或者前面提到的依赖于存在物理文件的流方法。您可以编辑通过将字节读入字符串,然后读入XML得到的字节,或者直接编辑字符串:
string docText = null;
byte[] byteArray = null;
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(documentPath, true))
{
    using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
    {
        docText = sr.ReadToEnd();  // <-- converts byte[] stream to string
    }
    // Play with the XML
    XmlDocument xml = new XmlDocument();
    xml.LoadXml(docText);  // the string contains the XML of the Word document
    XmlNodeList nodes = xml.GetElementsByTagName("w:body");
    XmlNode chiefBodyNode = nodes[0];
    // add paragraphs with AppendChild... 
    // remove a node by getting a ChildNode and removing it, like this...
    XmlNode firstParagraph = chiefBodyNode.ChildNodes[2];
    chiefBodyNode.RemoveChild(firstParagraph);
    // Or play with the string form
    docText = docText.Replace("John","Joe");
    // If you manipulated the XML, write it back to the string
    //docText = xml.OuterXml;  // comment out the line above if XML edits are all you want to do, and uncomment out this line
     // Save the file - yes, back to the file system - required
     using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
     {                    
        sw.Write(docText);
     }
 }
 // Read it back in as bytes
 byteArray = File.ReadAllBytes(documentPath); // new bytes, ready for DB saving
参考:

https://learn.microsoft.com/en-us/office/open-xml/how-to-search-and-replace-text-in-a-document-part

我知道这并不理想,但我已经搜索并没有找到一种直接编辑byte[]的方法,而不需要转换,包括写出文件,在Word中打开它进行编辑,然后基本上重新上传它以恢复新的字节。在重新读取文件之前执行byte[] byteArray = Encoding.UTF8.GetBytes(docText);会损坏它们,就像我尝试过的任何其他Encoding一样(UTF7, Default, Unicode, ASCII),正如我在最后一行尝试使用上面的WriteFile()函数将它们写回来时发现的那样。如果没有编码,只是使用File.ReadAllBytes()进行收集,然后使用WriteFile()将字节写回来,那么它工作得很好。

更新:

可以这样操作:

//byte[] byteArray = File.ReadAllBytes("Test.docx"); // you might be able to assign your bytes here, instead of from a file?
byte[] byteArray = GetByteArrayFromDatabase(fileId); // function you have for getting the document from the database
using (MemoryStream mem = new MemoryStream())
{
    mem.Write(byteArray, 0, (int)byteArray.Length);
    using (WordprocessingDocument wordDoc =
            WordprocessingDocument.Open(mem, true))
    {
        // do your updates -- see string or XML edits, above
        // Once done, you may need to save the changes....
        //wordDoc.MainDocumentPart.Document.Save();
    }
    // But you will still need to save it to the file system here....
    // You would update "documentPath" to a new name first...
    string documentPath = @"C:'temp'newDoc.docx";
    using (FileStream fileStream = new FileStream(documentPath,
            System.IO.FileMode.CreateNew))
    {
        mem.WriteTo(fileStream);
    }
}
// And then read the bytes back in, to save it to the database
byteArray = File.ReadAllBytes(documentPath); // new bytes, ready for DB saving
参考:

https://learn.microsoft.com/en-us/previous-versions/office/office-12//ee945362 (v = office.12)

但是请注意,即使这种方法也需要保存文档,然后再将其读入,以便将其保存为数据库的字节。如果文档在打开文档的那一行是.doc格式而不是.docx格式,它也会失败。

代替最后一节保存文件到文件系统,你可以把内存流保存回字节,一旦你在WordprocessingDocument.Open()块之外,但仍然在using (MemoryStream mem = new MemoryStream() { ... }语句内:

// Convert
byteArray = mem.ToArray();

这将使您的Word文档byte[] .