Поток в word файл

There are really only 2 ways to open a Word document programmatically — as a physical file or as a stream. There’s a «package», but that’s not really applicable.

The stream method is covered here: https://learn.microsoft.com/en-us/office/open-xml/how-to-open-a-word-processing-document-from-a-stream

But even it relies on there being a physical file in order to form the stream:

string strDoc = @"C:UsersPublicPublic DocumentsWord13.docx";
Stream stream = File.Open(strDoc, FileMode.Open);

The best solution I can offer would be to write the file out to a temp location where the service account for the application has permission to write:

string newDocument = @"C:temptest.docx";
WriteFile(byteArray, newDocument);

If it didn’t have permissions on the «temp» folder in my example, you would simply just add the service account of your application (application pool, if it’s a website) to have Full Control of the folder.

You’d use this WriteFile() function:

/// <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());
    }
}

From there, you can open it with OpenXML and edit the file. There’s no way to open a Word document in byte[] form directly into an instance of Word — Interop, OpenXML, or otherwise — because you need a documentPath, or the stream method mentioned earlier that relies on there being a physical file. You can edit the bytes you would get by reading the bytes into a string, and XML afterwards, or just edit the string, directly:

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

Reference:

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

I know it’s not ideal, but I have searched and not found a way to edit the byte[] directly without a conversion that involves writing out the file, opening it in Word for the edits, then essentially re-uploading it to recover the new bytes. Doing byte[] byteArray = Encoding.UTF8.GetBytes(docText); prior to re-reading the file will corrupt them, as would any other Encoding I tried (UTF7,Default,Unicode, ASCII), as I found when I tried to write them back out using my WriteFile() function, above, in that last line. When not encoded and simply collected using File.ReadAllBytes(), and then writing the bytes back out using WriteFile(), it worked fine.

Update:

It might be possible to manipulate the bytes like this:

//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:tempnewDoc.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

Reference:

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

But note that even this method will require saving the document, then reading it back in, in order to save it to bytes for the database. It will also fail if the document is in .doc format instead of .docx on that line where the document is being opened.

Instead of that last section for saving the file to the file system, you could just take the memory stream and save that back into bytes once you are outside of the WordprocessingDocument.Open() block, but still inside the using (MemoryStream mem = new MemoryStream() { ... } statement:

// Convert
byteArray = mem.ToArray();

This will have your Word document byte[].

In our WPF application, we must create a Word document and open it automatically.

Today we ask the user to specify the file name and location BEFORE we create the document and them open the file using the Process.Start method.

Now, I want to create the Word document in memory stream, open it and eventually, when the user decides to save the document in Microsoft Word, he will have to specify the location and name. So I will not be using the SaveFileDialog in my app.

This is similar to when you start Microsoft Word. A default document is created and when you click save, you will guided to the «save as» function.

How can I do that?

Deduplicator's user avatar

Deduplicator

44.3k7 gold badges65 silver badges115 bronze badges

asked Nov 25, 2015 at 20:02

Igor Kondrasovas's user avatar

Igor KondrasovasIgor Kondrasovas

1,4374 gold badges18 silver badges33 bronze badges

4

I don’t think you can do this purely on the memory stream. However, I would save the memory stream to a temporary file, by saving to the Temp folder or AppDatatemp or something like that with a randomly-generated name, and then mark that file as read-only. Then open word on that file (with System.Diagnostics.Process or however you are doing it), and since it is read-only, it will ask the user to save changes when they exit.

answered Nov 25, 2015 at 20:31

sovemp's user avatar

3

Just programmatically create a new Word document using the standard Microsoft.Interop.Word .Net namespace:

  • How to: Programmatically Create New Documents

Note that you might need to install MS-Office to do this.

Note, too, that your application can display it’s own «Save As» dialog (or, for that matter, could just use a hard-coded path) independent of Word. Your program chooses the path — and your program writes the Word document object if/when it’s ready.

Finally, here’s an alternative, open source library, DocX:

  • http://www.codeproject.com/Articles/660478/Csharp-Create-and-Manipulate-Word-Documents-Progra

  • How to: Open a word processing document from a stream (Open XML SDK)

ADDENDUM:

Thank you for your clarification:

  1. You’re using the OpenXML SDK (as an alternative to .Net Interop or DocX libraries I mentioned above). You’ve already created an in-memory document object.

  2. Now you want the user to be able to open the document object in Word (presumably to review it), before saving it (to a filename of his/her own choosing).

  3. You can’t (easily) do that :)

  4. One option, suggested by sovemp above:

    a. OpenXML writes to a temp file (so it can be opened in Word)

    b. Make the temp file read-only (to force the user to do an explicit «Save As»)

    c. Use .Net Process.Start() to invoke MSWord (specifying your temp file in your command line).

  5. Another option might be to use a «Preview Handler»:

    • http://www.codeproject.com/Articles/25465/Using-Vista-Preview-Handlers-in-a-WPF-Application

    • https://previewhandlers.codeplex.com/

  6. Still another option might be to serve the memory stream in a web browser, using HTTP ContentType «application/msword» (for example)

  7. Finally, if all you want is for the user to specify a filename (if «preview» isn’t essential), you can always pop up your own «Save as» dialog and write document to disk directly from OpenXML.

answered Nov 25, 2015 at 20:14

paulsm4's user avatar

paulsm4paulsm4

113k16 gold badges135 silver badges188 bronze badges

3

В нашем приложении WPF мы должны создать документ Word и открыть его автоматически.

Сегодня мы просим пользователя указать имя и местоположение файла ДО того, как мы создадим документ и откроем файл с помощью метода Process.Start.

Теперь я хочу создать документ Word в потоке памяти, открыть его и, в конце концов, когда пользователь решит сохранить документ в Microsoft Word, ему нужно будет указать местоположение и имя. Поэтому я не буду использовать SaveFileDialog в своем приложении.

Это похоже на запуск Microsoft Word. Будет создан документ по умолчанию, и когда вы нажмете «Сохранить», вы перейдете к функции «Сохранить как».

Как я могу это сделать?

2 ответа

Я не думаю, что вы можете сделать это исключительно в потоке памяти. Однако я бы сохранил поток памяти во временный файл, сохранив его в папку Temp или AppDatatemp или что-то подобное со случайно сгенерированным именем, а затем пометив этот файл как доступный только для чтения. Затем откройте слово в этом файле (с помощью System.Diagnostics.Process или как вы это делаете), и, поскольку он доступен только для чтения, он попросит пользователя сохранить изменения при выходе.


4

sovemp
25 Ноя 2015 в 23:31

Просто программно создайте новый документ Word, используя стандартное пространство имен Microsoft.Interop.Word .Net:

  • Практическое руководство. Программное создание новых документов

Обратите внимание, что для этого вам может потребоваться установить MS-Office.

Также обратите внимание, что ваше приложение может отображать собственное диалоговое окно «Сохранить как» (или, если уж на то пошло, может просто использовать жестко заданный путь), независимое от Word. Ваша программа выбирает путь — и ваша программа записывает объект документа Word, если/когда он будет готов.

Наконец, вот альтернативная библиотека с открытым исходным кодом, DocX:

  • http://www.codeproject.com/Articles /660478/Csharp-Create-and-Manipulate-Word-Documents-Progra

  • Как открыть текстовый документ из потока (Open XML SDK)< /а>

ДОБАВЛЕНИЕ:

Благодарим Вас за разъяснения:

  1. Вы используете OpenXML SDK (в качестве альтернативы библиотекам .Net Interop или DocX, о которых я упоминал выше). Вы уже создали объект документа в памяти.

  2. Теперь вы хотите, чтобы пользователь мог открыть объект документа в Word (предположительно, чтобы просмотреть его) перед его сохранением (с именем файла по своему выбору).

  3. Вы не можете (легко) сделать это :)

  4. Один вариант, предложенный sovemp выше:

    а. OpenXML записывает во временный файл (чтобы его можно было открыть в Word)

    б. Сделайте временный файл доступным только для чтения (чтобы заставить пользователя сделать явное «Сохранить как»)

    в. Используйте .Net Process.Start() для вызова MSWord (указав временный файл в командной строке).

  5. Другим вариантом может быть использование «обработчика предварительного просмотра»:

    • http:/ /www.codeproject.com/Articles/25465/Использование-Vista-Preview-Handlers-in-a-WPF-Application

    • https://previewhandlers.codeplex.com/

  6. Еще одним вариантом может быть обслуживание потока памяти в веб-браузере с использованием HTTP ContentType «application/msword» (например)

  7. Наконец, если все, что вам нужно, это чтобы пользователь указал имя файла (если «предварительный просмотр» не обязателен), вы всегда можете открыть свое собственное диалоговое окно «Сохранить как» и записать документ на диск непосредственно из OpenXML.


3

paulsm4
26 Ноя 2015 в 00:17

Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.

Страницы 1

Чтобы отправить ответ, вы должны войти или зарегистрироваться

Сообщений [ 2 ]

1 11.08.2015 12:03:53

  • Запись данных в текстовый файл и из файла с помощью ADODB.Stream
  • Alex_Gur
  • Модератор
  • Неактивен
  • Откуда: Москва
  • Зарегистрирован: 28.07.2011
  • Сообщений: 2,758
  • Поблагодарили: 492

Тема: Запись данных в текстовый файл и из файла с помощью ADODB.Stream

Запись данных в текстовый файл

ADODB – библиотека доступа к базам данных.
ADODB.Stream — в данном случае, проще говоря, это поток для связи с файлом.

Предварительно в файле Word должен быть выделен некоторый отрывок, который записывается в текстовый файл.
Файл Word с выделенным отрывком должен быть активным.
Для записи можно применить следующий макрос:

Sub Writer_To1()
        Dim strUnicode As String  'Содержание записываемого файла
        strUnicode = ""
        Dim Par As Paragraph
        For Each Par In Selection.Paragraphs
            strUnicode = strUnicode & Par.Range.Text & vbLf
        Next Par
        
        Dim FileName As String  'Полное имя записываемого файла
        FileName = ActiveDocument.FullName & ".txt"
        Dim oFS: Set oFS = CreateObject("Scripting.FileSystemObject")
    '    Dim sTFSpec: sTFSpec = oFS.GetAbsolutePathName(FileName)
        If oFS.FileExists(FileName) Then
            oFS.DeleteFile FileName   'Если файл существует, то его нужно удалить
        End If
        
        Dim oTo: Set oTo = CreateObject("ADODB.Stream") 'Поток для связи с файлом
        With oTo
            .Type = 2 'Тип потока: 1 - бинарный; 2 - текстовый
            .Charset = "Windows-1251"  'кодировка
            .Open                    'открытие потока
            .WriteText strUnicode    'запись текста из переменной strUnicode
            .SaveToFile FileName     'запись в файл FileName
            .Close                   'закрытие потока
        End With
    End Sub

Выделенный фрагмент записывается в текстовый файл в той же папке, в которой размещен исходный файл Word.

Удобной и приятной работы в Word!
Перевести спасибо на Яндекс кошелёк — 41001162202962; на WebMoney — R581830807057.

2 Ответ от Alex_Gur 11.08.2015 12:34:21

  • Запись данных в текстовый файл и из файла с помощью ADODB.Stream
  • Alex_Gur
  • Модератор
  • Неактивен
  • Откуда: Москва
  • Зарегистрирован: 28.07.2011
  • Сообщений: 2,758
  • Поблагодарили: 492

Re: Запись данных в текстовый файл и из файла с помощью ADODB.Stream

Загрузка из файла

Загрузка производится в конец активного файла Word из текстового файла с именем «1.txt», размещенного в той же папке.

Sub Reader_From1()
    Dim strUnicode As String  'Переменная для ввода данных из файла
    Dim myRange As Range
    
    Selection.EndKey Unit:=wdStory  'переход в конец файла
    Selection.TypeParagraph         'новая строка
    
    Dim FileName As String  'Полное имя вводимого файла
    FileName = ActiveDocument.Path & "1.txt"
    
    Dim oTo: Set oTo = CreateObject("ADODB.Stream") 'Поток для связи с файлом
    With oTo
        .Type = 2 'Тип потока: 1 - бинарный; 2 - текстовый
        .Charset = "Windows-1251"  'кодировка
        .Open                    'открытие потока
        .LoadFromFile FileName   'считывание из файла FileName
        strUnicode = .ReadText   'загрузка текста в переменную strUnicode
        .Close                   'закрытие потока
    End With
    
    Selection.TypeText strUnicode  'вставка переменной в файл
End Sub

Удобной и приятной работы в Word!
Перевести спасибо на Яндекс кошелёк — 41001162202962; на WebMoney — R581830807057.

Сообщений [ 2 ]

Страницы 1

Чтобы отправить ответ, вы должны войти или зарегистрироваться

Похожие темы

  • Исправить запись данных из формы
  • Как отсоединить источник данных для рассылки от файла Word
  • Открытие файла из неактивной папки с помощью окна Открытие документа
  • Запись исполняемого кода
  • запись скриптов в word
  • Запись действий пользователя
  • Запись макроса макрорекодером
  • Запись макроса макросом возможно?

Запись данных в текстовый файл и из файла с помощью ADODB.Stream

Для всех пользователей текстового редактора Microsoft Word будет полезно познакомиться со встроенными функциями и настройками этой программы. Наш сайт о Microsoft Office Word даст ответ про: как включить предпросмотр в ворд 2010.

На форуме сайта Ворд Эксперт вам предложат различные варианты настроек, в зависимости от поставленных задач. Наш сайт о Microsoft Office Word даст ответ про: тормозят word файлы.
Так существуют схемы для быстрого удаления лишних пробелов из текста, переформатирования и оформления в одном стиле различных кусков, работы с таблицами и многого другого. На портале о Microsoft Office Word вы узнаете про: как поменять нумерацию части списка в word 2003.

Здесь вы найдете шаблоны для часто повторяющихся схем оформления текста, макросы практически для любых операций, готовые решения и пошаговые инструкции для написания. На портале о Microsoft Office Word вы узнаете про: все про вставку в microsoft word.
Также вы можете оставить заявку на любую работу, связанную с Вордом.

 
bss
 
(2011-02-16 17:26)
[0]

Имеем дело с COM/OLE-объектом «Word.Application» и его документами.

Есть ли способ загрузить файл из памяти, а не с диска? Не OLE-информацию всю, а допустим имеем из базы Stream с данными в формате файла .doc

Также интересует сохранение.


 
Игорь Шевченко ©
 
(2011-02-16 18:39)
[1]

сохранить во временный файл, загрузить из файла


 
bss
 
(2011-02-16 18:54)
[2]

Фиг, мы легких путей не ищем )))

Вот мое творчество.

Допустим, OleDocument — Это документ Word»а (или Workbook эксела):

procedure TfrmRG_DocOut.SaveDocumentToStream(Stream: TStream);
var
 TempStorage: IStorage;
 PersistStorage: IPersistStorage;
 TempLockBytes: ILockBytes;
 DataHandle: HGlobal;
 Buffer: Pointer;
begin
 (IDispatch(OleDocument) as IOleObject).QueryInterface(IPersistStorage, PersistStorage);
 if PersistStorage <> nil then
 begin
   OleCheck(CreateILockBytesOnHGlobal(0, True, TempLockBytes));
   OleCheck(StgCreateDocfileOnILockBytes(TempLockBytes, STGM_READWRITE
     or STGM_SHARE_EXCLUSIVE or STGM_CREATE, 0, TempStorage));
   OleCheck(OleSave(PersistStorage, TempStorage, False));
   PersistStorage.SaveCompleted(nil);

   OleCheck(GetHGlobalFromILockBytes(TempLockBytes, DataHandle));

   Buffer := GlobalLock(DataHandle);
   try
     Stream.Size := GlobalSize(DataHandle) ;
     Stream.Position := 0;
     Stream.WriteBuffer(Buffer^, Stream.Size);
   finally
     GlobalUnlock(DataHandle);
   end;
 end;
end;


 
Игорь Шевченко ©
 
(2011-02-16 20:33)
[3]


> Вот мое творчество.

Как бы вас всех, творцов, собрать в одно место… :)


 
Leonid Troyanovsky ©
 
(2011-02-16 22:42)
[4]


> Игорь Шевченко ©   (16.02.11 20:33) [3]

> Как бы вас всех, творцов, собрать в одно место… :)


В дом творчества.
Скажем, Верзоль.


Regards, LVT.


 
Игорь Шевченко ©
 
(2011-02-16 23:10)
[5]


> Скажем, Верзоль.

оценил :)


 
bss
 
(2011-02-17 11:16)
[6]

Игорь, хотите сказать, что код не очень хороший? В целом, принципы взяты из кодов VCL, так шо без наездов плиз ))


 
Inovet ©
 
(2011-02-17 11:22)
[7]

> [4] Leonid Troyanovsky ©   (16.02.11 22:42)
> В дом творчества.
> Скажем, Верзоль.

Путин вчера пердложил владивостокским таможенникам заняться творчеством в ДК Таможенник, а не на рабочем месте клипы снимать о своей рулезной крутизне.


 
Anatoly Podgoretsky ©
 
(2011-02-17 11:33)
[8]


> Игорь, хотите сказать, что код не очень хороший? В целом,
>  принципы взяты из кодов VCL, так шо без наездов плиз ))

Ссылка на чужой код не состоятельна, откуда бы этот код не был взят.


Понравилась статья? Поделить с друзьями:
  • Потеряна связь с microsoft excel для просмотра присоединенных листов
  • Потеря текста при объединении ячейки в excel
  • Посчитать сумму в нескольких ячейках в excel
  • Посчитать сумму в excel с запятыми
  • Пот скачать бесплатно word