我有一个字节流,实际上(如果正确)将形成一个有效的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文档后,我想对关键字进行一些解析。
有什么想法吗?
答案 0 :(得分:0)
需要注意的一件重要事项:在数据库中存储文件通常不是一个好设计。
答案 1 :(得分:0)
可能没有任何直截了当的方法。我找到了几个搜索它的解决方案:
我不知道这是否适合您,但显然API并未提供您所追求的(不幸的是)。
答案 2 :(得分:0)
你可以看看Sharepoint如何解决这个问题。他们为存储在数据库中的文档创建了一个Web界面。
在您的应用程序中创建或嵌入可以向Word提供页面的Web服务器并不难。您甚至不必使用标准端口。
答案 3 :(得分:0)
实际上只有两种方法可以以编程方式打开Word文档-作为物理文件或作为流。有一个“包”,但这并不真正适用。
但即使它依赖于存在物理文件才能形成流:
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打开它并编辑文件。无法将字节[]格式的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://docs.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
,{{1 }}),这是我在上面的最后一行中尝试使用我的Unicode
函数将其写回时发现的。如果不进行编码,而只是使用ASCII
进行收集,然后使用WriteFile()
将字节写回,则可以正常工作。
更新:
可能可以这样操作字节:
File.ReadAllBytes()
参考:
https://docs.microsoft.com/en-us/previous-versions/office/office-12//ee945362(v=office.12)
但是请注意,即使此方法也需要保存文档,然后将其读回,以将其保存到数据库的字节中。如果文档的格式为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
,也会失败。
如果您不在.doc
块之外但仍在{{1内,则可以直接使用内存流并将其保存回字节中,而不是将文件保存到文件系统中的最后一部分。 }}语句:
.docx
这将有您的Word文档WordprocessingDocument.Open()
。