Почему размер файла увеличивается каждый раз, когда текстовый документ сохраняется с помощью VBA?

У меня есть макрос VBA, который я написал, который берет данные из электронной таблицы для создания текстовых документов.

По большей части вся генерируемая информация точно такая же, за исключением нескольких полей, которые обозначают контактную информацию и суммы. Все файлы начинаются с размера 17 КБ, но по мере прохождения макроса по электронной таблице размер этих файлов увеличивается. После примерно 2500 сохранений размер файлов достиг 48 КБ.

Я не уверен, почему это происходит. Я подумал, что, может быть, какие-то метаданные сохраняются после каждого удаления и повторной записи документа.

Я пробовал несколько вещей для удаления метаданных, но не уверен, что делаю это правильно, так как я не так много могу найти по этой проблеме.

Пытаясь сделать этот запуск немного быстрее, я создал макрос, чтобы открыть пустой документ Word, а затем, когда он просматривает все строки в электронной таблице, копирует окончательную информацию в слово doc, SaveAs - уникальное значение в папке. затем удаляет содержимое слова doc, а затем выполняет все заново, пока оно не будет повторено по всем строкам на листе.

Есть ли что-то в том, как я создаю свои файлы, что вызывает рост файлов Word docx?

После просмотра каждого созданного файла (сотни) он, кажется, увеличивается в среднем на 20b с каждым новым сгенерированным документом. Так что размер файла медленно, но постоянно растет с каждым сохранением.

Вот пример того, как выглядит рост каждого нового сохраненного документа.

введите описание изображения здесь

Вот пример того, как КБ со временем растут.

введите описание изображения здесь

Вот общий макрос в урезанном виде.

Sub GenerateLetterForSelectedMonth()
    Dim temp_wb, data_wb As Workbook
    Dim temp_ws, data_ws As Worksheet
    Dim ltr_str1, ltr_str2, wb_dir, file_path As String
    Dim account_num, cust_name, non_etf_amt, etf_amt, plcmt_amt, mex_act, adr1, adr2, city, state, zip, country, cont_name As String
    Dim last_row1 As Long
    Dim objWord As Object
    ' Dim objWord As New Word.Application
    Dim objDoc As Word.Document
    Dim fd As Office.FileDialog

    Set temp_wb = ActiveWorkbook
    Set temp_ws = temp_wb.Worksheets(1)
    wb_dir = temp_wb.Path

    ' Select file to process '
    Set fd = Application.FileDialog(msoFileDialogFilePicker)

    ' open file to process '
    Set data_wb = Workbooks.Open(file_path)
    Set data_ws = data_wb.Worksheets(1)

    ' get last row of file being processed '
    last_row1 = data_ws.Range("A" & data_ws.Rows.Count).End(xlUp).Row

    ' check for todays folder if not exist then create '
    Dim path_ As String
    path_ = wb_dir & "\DOCS " & Format(Now, "MMMM-dd-yyyy")

    With CreateObject("Scripting.FileSystemObject")
        If Not .FolderExists(path_) Then .CreateFolder path_
    End With


    Set objWord = CreateObject("Word.Application")
    Set objDoc = objWord.Documents.Add
    objWord.Visible = False

    For i = 2 To last_row1

        mex_act = UCase(data_ws.Cells(i, 7).Value)
        account_num = data_ws.Cells(i, 1)
        cust_name = data_ws.Cells(i, 2)
        non_etf_amt = data_ws.Cells(i, 3)
        etf_amt = data_ws.Cells(i, 5)
        plcmt_amt = data_ws.Cells(i, 6)
        adr1 = data_ws.Cells(i, 8)
        adr2 = data_ws.Cells(i, 9)
        city = data_ws.Cells(i, 10)
        state = data_ws.Cells(i, 11)
        zip = data_ws.Cells(i, 12)
        country = data_ws.Cells(i, 13)
        cont_name = WorksheetFunction.Proper(data_ws.Cells(i, 14))

        temp_ws.Cells(3, 1).Value = _
            Format(Now, "MMMM-dd-yyyy") & vbNewLine & cust_name & vbCr & adr1 & " " & adr2 & vbCr & city & ", " & state & " " & zip & vbNewLine & _
            "redacted for post " & "****" & Mid(account_num, 5, 10) & vbNewLine & "Dear " & cont_name & ":" & vbNewLine & "redacted for post" & plcmt_amt & _
            "redacted for post" & vbNewLine & "redacted for post" & non_etf_amt & vbCr & "redacted for post" & etf_amt & vbNewLine & "redacted for post" _

        'Copy the range Which you want to paste in a New Word Document
        temp_ws.Range("A2:A6").Copy

        With objWord
            .Selection.WholeStory
            .Selection.Paste
            .DefaultTableSeparator = " "
        End With

        objWord.ActiveDocument.RemoveDocumentInformation (wdRDIAll)
        objDoc.SaveAs Filename:=path_ & "\" & data_ws.Cells(i, 1)

        With objWord
            objDoc.Range(0, 0).Select
            .Selection.WholeStory
            .Selection.Delete
        End With
        Debug.Print (i)
    Next i

    objWord.Quit SaveChanges:=wdDoNotSaveChanges

End Sub

person Mike - SMT    schedule 11.07.2019    source источник
comment
Если я хорошо понял: случай 1 ваш код генерирует 10 идентичных текстовых документов за один раз (разница только в информации, но в количестве одинаково). Первый файл будет размером 17 КБ, 10-й файл будет иметь размер 17 КБ + 20 КБ * 9, даже если он содержит такое же количество информации, что и первый. случай 2: вы запускаете макрос для создания 1 однословного документа размером 17 КБ. Вы повторяете это упражнение еще 9 раз, и размер каждого документа составляет 17 КБ (потому что каждый документ является первым в каждом запуске). Я правильно понимаю?   -  person Matteo NNZ    schedule 11.07.2019
comment
Вы отслеживаете изменения? (См .: Вкладка "Обзор")   -  person K.Dᴀᴠɪs    schedule 11.07.2019
comment
да. Думаю, я уже нашел решение. Я изменил раздел, в котором после сохранения objDoc он выполняет .Close, затем Set objDoc = Nothing, и это, похоже, устранило рост файла. Итак, что-то в objDoc сохраняло некоторую информацию после каждого сохранения. Я просто не знаю, что на данный момент.   -  person Mike - SMT    schedule 11.07.2019
comment
@MatteoNNZ размеры файлов увеличивались только на 5-20 байт за одно сохранение. Это в сумме составляет 48 КБ по сравнению с 2500 создаваемыми документами. Я по крайней мере выяснил, что часть, которая получала данные при сохранении, была фактическим объектом документа в объекте слова.   -  person Mike - SMT    schedule 11.07.2019
comment
Повторная инициализация objDoc - это то, что я собирался предложить, если ваш ответ был положительным. Рад, что ты нашел решение. Я не знаю, почему он так себя ведет, но если вы хотите выяснить это ради науки, вы можете сгенерировать 10 образцов файлов, изменить их расширение на .zip и открыть каждый из них с помощью программы просмотра папок: вы должны определить совокупная информация, которая, скорее всего, будет данными кеша из вашего предыдущего сохранения.   -  person Matteo NNZ    schedule 11.07.2019
comment
@MatteoNNZ, если это данные кеша, есть ли способ (кроме повторной инициализации objDoc) передать слово через VBA для сброса кеша?   -  person Mike - SMT    schedule 11.07.2019
comment
Я не думаю, что код MS Word предоставляет такой API для сброса кеша. Я думаю, что объект ведет себя как стандартный документ Word (а Word для конечных пользователей не предлагает ни одной из этих функций). Что не так с его повторной инициализацией при каждом запуске? Это замедляет ваш макрос?   -  person Matteo NNZ    schedule 11.07.2019
comment
Это было, когда я повторно инициализировал objWord, но, похоже, он не замедляется или, по крайней мере, не сильно, когда я повторно инициализирую объект 'objDoc' в слове object, так что сейчас это будет работать. Перед тем, как опубликовать здесь, я пробовал использовать «objWord», и он сильно замедлился.   -  person Mike - SMT    schedule 11.07.2019


Ответы (1)


После некоторой догадки я выяснил, по крайней мере, какой объект удерживал дату при каждом сохранении файла.

В итоге мне пришлось полностью закрыть и установить Nothing objDoc, а затем повторно добавить objDoc при каждом запуске цикла. Это избавило меня от увеличения размера файла, на который я смотрел.

Я до сих пор не знаю, почему он рос, поэтому, если кто-то знает это, я хотел бы знать наверняка, почему это произошло, а не только с тем, с чем это происходило.

Ниже приведен новый код, если кому-то интересно:

Sub GenerateLetterForSelectedMonth()
    Dim temp_wb, data_wb As Workbook
    Dim temp_ws, data_ws As Worksheet
    Dim ltr_str1, ltr_str2, wb_dir, file_path As String
    Dim account_num, cust_name, non_etf_amt, etf_amt, plcmt_amt, mex_act, adr1, adr2, city, state, zip, country, cont_name As String
    Dim last_row1 As Long
    Dim objWord As Object
    ' Dim objWord As New Word.Application
    Dim objDoc As Word.Document
    Dim fd As Office.FileDialog

    Set temp_wb = ActiveWorkbook
    Set temp_ws = temp_wb.Worksheets(1)
    wb_dir = temp_wb.Path

    ' Select file to process '
    Set fd = Application.FileDialog(msoFileDialogFilePicker)

    ' open file to process '
    Set data_wb = Workbooks.Open(file_path)
    Set data_ws = data_wb.Worksheets(1)

    ' get last row of file being processed '
    last_row1 = data_ws.Range("A" & data_ws.Rows.Count).End(xlUp).Row

    ' check for todays folder if not exist then create '
    Dim path_ As String
    path_ = wb_dir & "\DOCS " & Format(Now, "MMMM-dd-yyyy")

    With CreateObject("Scripting.FileSystemObject")
        If Not .FolderExists(path_) Then .CreateFolder path_
    End With


    Set objWord = CreateObject("Word.Application")

    For i = 2 To last_row1
        Set objDoc = objWord.Documents.Add ' ADDED THIS LINE
        mex_act = UCase(data_ws.Cells(i, 7).Value)
        account_num = data_ws.Cells(i, 1)
        cust_name = data_ws.Cells(i, 2)
        non_etf_amt = data_ws.Cells(i, 3)
        etf_amt = data_ws.Cells(i, 5)
        plcmt_amt = data_ws.Cells(i, 6)
        adr1 = data_ws.Cells(i, 8)
        adr2 = data_ws.Cells(i, 9)
        city = data_ws.Cells(i, 10)
        state = data_ws.Cells(i, 11)
        zip = data_ws.Cells(i, 12)
        country = data_ws.Cells(i, 13)
        cont_name = WorksheetFunction.Proper(data_ws.Cells(i, 14))

        temp_ws.Cells(3, 1).Value = _
            Format(Now, "MMMM-dd-yyyy") & vbNewLine & cust_name & vbCr & adr1 & " " & adr2 & vbCr & city & ", " & state & " " & zip & vbNewLine & _
            "redacted for post " & "****" & Mid(account_num, 5, 10) & vbNewLine & "Dear " & cont_name & ":" & vbNewLine & "redacted for post" & plcmt_amt & _
            "redacted for post" & vbNewLine & "redacted for post" & non_etf_amt & vbCr & "redacted for post" & etf_amt & vbNewLine & "redacted for post" _

        'Copy the range Which you want to paste in a New Word Document
        temp_ws.Range("A2:A6").Copy

        With objWord
            .Selection.WholeStory
            .Selection.Paste
            .DefaultTableSeparator = " "
        End With

        objWord.ActiveDocument.RemoveDocumentInformation (wdRDIAll)
        objDoc.SaveAs Filename:=path_ & "\" & data_ws.Cells(i, 1)
        objDoc.Close  ' ADDED THIS LINE
        Set objDoc = Nothing  ' ADDED THIS LINE

    Next i

    objWord.Quit SaveChanges:=wdDoNotSaveChanges

End Sub
person Mike - SMT    schedule 11.07.2019
comment
Я думал об этом, пытаясь выкопать все, что я слышал и читал за последние 20 лет ... Лучше всего было бы спросить Венеру конечного пользователя, поскольку у кого-то там может быть больше опыта с поведением при повторном чтении. сохранение документа снова и снова. Важно: укажите версию Word и НЕ упоминайте код. Вы также можете открыть два таких документа в Open XML SDK Productivity Tool и использовать функцию сравнения, чтобы увидеть, чем отличается лежащий в основе Word Open XML - это должно дать вам важные подсказки ... - person Cindy Meister; 13.07.2019
comment
... Вы также можете попробовать повторно открыть один из них, затем сохранить и снова закрыть (что может удалить остатки, оставшиеся от предыдущего редактирования). В основном Word сохраняет информацию об отмене за пределами документа, но вполне может выполнять какое-то внутреннее отслеживание внутри него ... - person Cindy Meister; 13.07.2019
comment
@CindyMeister параметры повторного открытия сильно замедляют работу макроса. То же самое и с сохранением закрытия, а затем с созданием нового объекта слова. Мне нужно было исправить проблему без значительного увеличения времени, затрачиваемого на выполнение макроса. Я, вероятно, отправлюсь к конечному пользователю и опубликую, когда вернусь к работе. Спасибо за информацию. - person Mike - SMT; 14.07.2019
comment
Вы спросили почему это произошло. Мои замечания были направлены на это, а не как возможные подходы к достижению цели. Для достижения своей цели вы должны начать с шаблона (dotx) и использовать Documents.Add для каждого нового документа, а не пытаться повторно использовать тот же документ. Это стандартное использование Word, будь то для конечных пользователей или разработчиков ... - person Cindy Meister; 14.07.2019