如何使用字节流形成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一个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[]
.