Performance VBA宏每次执行都会变慢
我有一个宏可以逐行读取.txt文件。我检查每一行是否等于某个新页面的代码,说它是“下一个”——如果是,则插入分页符。在出现一定数量的“下一步”之后,整个文档将导出为pdf。然后删除.doc的内容,我继续读取并导出txt文件,直到EOF 问题:宏每次执行都会变慢 我的测试文件有27300行/791KB(实际文件在10到100MB之间)。在启动宏之前,WINWORD进程占用40K内存。每次执行宏后,内存使用量都会增加Performance VBA宏每次执行都会变慢,performance,vba,ms-word,Performance,Vba,Ms Word,我有一个宏可以逐行读取.txt文件。我检查每一行是否等于某个新页面的代码,说它是“下一个”——如果是,则插入分页符。在出现一定数量的“下一步”之后,整个文档将导出为pdf。然后删除.doc的内容,我继续读取并导出txt文件,直到EOF 问题:宏每次执行都会变慢 我的测试文件有27300行/791KB(实际文件在10到100MB之间)。在启动宏之前,WINWORD进程占用40K内存。每次执行宏后,内存使用量都会增加 Time Max.MemoryUsage MemoryUs
Time Max.MemoryUsage MemoryUsageAfterwards
Run1 11.9s 70K 64K
Run2 19.7s 90K 84K
Run3 22.3s 99K 92K
我知道部分解决方案是手动关闭并重新打开.doc文件,然后以next.txt文件作为输入运行宏。但是,即使在运行一次宏之后关闭Word也需要很长时间,尽管文件中没有我可以看到的内容
我想问的是,是否有其他方法可以解决这个问题,我认为这是一个记忆清除问题
我的代码:
打开文档时:
Private Sub Document_Open()
ReadAndSplit
End Sub
全局变量和声明:
Option Explicit
'---------------------------------------------------------------------------
' GLOBAL VARIABLES
'---------------------------------------------------------------------------
Public numOfBreaks As Integer ' number of page breaks made
Public numOfPdfs As Integer ' number of currently printed pdf
Public filePrefix As String ' name prefix for .pdf files
Public sFileName As String ' name of Input File
Public breakAfter As Integer ' print after this number of NEXT
Public cancelActive As Boolean ' cancel Button pressed? (for exit)
主要宏:
Sub ReadAndSplit()
'---------------------------------------------------------------------------
' VARIABLES
'---------------------------------------------------------------------------
Dim sLine As String ' line from text file
Dim numOfLines As Long ' number of lines read from .txt input
Dim execStart As Single ' starting time of script execution
Dim nextPage As Boolean ' indicates if new document beginns
'---------------------------------------------------------------------------
' INITIAL PROCESSING
'---------------------------------------------------------------------------
Application.Visible = False
Application.ScreenUpdating = False
Selection.WholeStory ' clear the document
Selection.Delete
UserForm1.Show ' show user dialog
If cancelActive Then ' Cancel button handling
Application.Visible = True
Exit Sub
End If
With ActiveDocument.PageSetup ' set page margins & orientation
.TopMargin = 0.1
.BottomMargin = 0.1
.LeftMargin = 0.1
.RightMargin = 0.1
End With
'---------------------------------------------------------------------------
' MAIN PROCESSING
'---------------------------------------------------------------------------
numOfBreaks = 0 ' GLOBALS
numOfPdfs = 1
numOfLines = 0 ' LOCALS
nextPage = True
execStart = Timer
Open sFileName For Input As #1
Do While Not EOF(1)
If nextPage Then ' write 2 empty lines
Selection.TypeText (vbNewLine & vbNewLine)
nextPage = False
End If
Line Input #1, sLine ' read 1 line from input
numOfLines = numOfLines + 1 ' count lines
If sLine <> "NEXT" Then ' test for NEXT
Selection.TypeText (sLine) & vbNewLine ' write line from input .txt
Else
Selection.InsertBreak Type:=wdPageBreak ' NEXT -> new page
numOfBreaks = numOfBreaks + 1 ' count new receipts
If numOfBreaks = breakAfter Then ' compare with PARAM
PrintAsPDF ' export to pdf
numOfBreaks = 0
End If
nextPage = True ' switch new page on
End If
Loop
If numOfBreaks <> 0 Then ' print out the last part
PrintAsPDF
End If
Close #1
Debug.Print vbNewLine & "-----EXECUTION-----"
Debug.Print Now
Debug.Print "Lines: " & numOfLines
Debug.Print "Time: " & (Timer - execStart)
Debug.Print "-------------------" & vbNewLine
Selection.WholeStory ' clear the word document
Selection.Delete
Application.Visible = True
End Sub
用户表单代码:
'---------------------------------------------------------------------------
' OK BUTTON
'---------------------------------------------------------------------------
Private Sub OKButton_Click()
Dim inputFileOk As Boolean ' input file path
Dim inputSplitOk As Boolean ' split
Dim prefixOk As Boolean ' prefix
If FileTxtBox.Text = vbNullString Then ' validate file path
inputFileOk = False
MsgBox ("File path missing!")
Else
inputFileOk = True
End If
If IsNumeric(SplitTxtBox.Text) Then ' validate breakAfter
breakAfter = SplitTxtBox.Text
inputSplitOk = True
Else
MsgBox ("Non-numeric value for SPLIT!")
End If
If PrefixTxtBox <> vbNullString Then ' validate prefix
filePrefix = PrefixTxtBox.Text
prefixOk = True
Else
MsgBox ("Missing prefix!")
End If
' check if all inputs are ok
If inputFileOk And inputSplitOk And prefixOk Then
cancelActive = False
Unload Me
End If
End Sub
'---------------------------------------------------------------------------
' CANCEL BUTTON
'---------------------------------------------------------------------------
Private Sub CancelButton_Click()
cancelActive = True ' for script termination
Unload Me
End Sub
'---------------------------------------------------------------------------
' FILE BUTTON
'---------------------------------------------------------------------------
Private Sub FileButton_Click()
Dim i As Integer ' file selection index
' show file chooser dialog and assign selected file to sFileName
Application.FileDialog(msoFileDialogOpen).AllowMultiSelect = False
i = Application.FileDialog(msoFileDialogOpen).Show
If i <> 0 Then
sFileName = Application.FileDialog(msoFileDialogOpen).SelectedItems(1)
FileTxtBox.Text = sFileName
End If
End Sub
'---------------------------------------------------------------------------
'确定按钮
'---------------------------------------------------------------------------
私有子按钮点击()
Dim inputFileOk作为布尔输入文件路径
Dim inputSplitOk作为布尔值“拆分”
作为布尔“前缀”的Dim prefixOk
如果FileTxtBox.Text=vbNullString,则“验证文件路径”
inputFileOk=False
MsgBox(“文件路径丢失!”)
其他的
inputFileOk=True
如果结束
如果是数字(SplitTxtBox.Text),则“验证breakAfter”
breakAfter=SplitTxtBox.Text
inputSplitOk=True
其他的
MsgBox(“拆分的非数值!”)
如果结束
如果PrefixtBox vbNullString,则“验证前缀”
filePrefix=prefixtxbox.Text
prefixOk=True
其他的
MsgBox(“缺少前缀!”)
如果结束
'检查所有输入是否正常
如果inputFileOk和inputSplitOk以及prefixOk,则
取消活动=错误
卸下我
如果结束
端接头
'---------------------------------------------------------------------------
'取消按钮
'---------------------------------------------------------------------------
专用子按钮取消单击()
对于脚本终止,cancelActive=True
卸下我
端接头
'---------------------------------------------------------------------------
'文件按钮
'---------------------------------------------------------------------------
私有子文件按钮\单击()
Dim i作为整数的文件选择索引
'显示文件选择器对话框并将所选文件分配给sFileName
Application.FileDialog(msoFileDialogOpen).AllowMultiSelect=False
i=Application.FileDialog(msoFileDialogOpen.Show)
如果我是0那么
sFileName=Application.FileDialog(msoFileDialogOpen)。选择editems(1)
FileTxtBox.Text=sFileName
如果结束
端接头
Word在“临时”文件中存储大量信息,以便跟踪“无限”撤消。如果在不保存文件或不清除撤消缓冲区的情况下执行大量操作,则会减慢Word的速度。因此,我建议:
为了释放资源。我认为我们需要查看您的全部代码,以回答是什么让宏变慢了。也许试着把你的全部代码发布到codereview.stackexchange.com上?这可能是一个很好的问题,只要:(a)代码有效,(B)它不是假设的或不完整的。如果您选择转到,请在发帖前阅读。如果您有任何问题或担忧,请加入我们的网站。您是否尝试过在没有打印PDF的情况下运行。我在过去遇到过pdf的问题,可能值得将此过程作为一个原因加以消除。在您的位置上,我将看1)清除撤消缓冲区和2)保存(空)文档。Word存储所有内容以启用“撤消”,这可能会减慢速度。我在移动设备上,因此无法检查清除撤消的确切语法,但类似于Document.Undo.Clear…请不要编辑问题以包含解决方案(即答案)。这里关于堆栈溢出的正确方法是“回答”这个问题。
'---------------------------------------------------------------------------
' OK BUTTON
'---------------------------------------------------------------------------
Private Sub OKButton_Click()
Dim inputFileOk As Boolean ' input file path
Dim inputSplitOk As Boolean ' split
Dim prefixOk As Boolean ' prefix
If FileTxtBox.Text = vbNullString Then ' validate file path
inputFileOk = False
MsgBox ("File path missing!")
Else
inputFileOk = True
End If
If IsNumeric(SplitTxtBox.Text) Then ' validate breakAfter
breakAfter = SplitTxtBox.Text
inputSplitOk = True
Else
MsgBox ("Non-numeric value for SPLIT!")
End If
If PrefixTxtBox <> vbNullString Then ' validate prefix
filePrefix = PrefixTxtBox.Text
prefixOk = True
Else
MsgBox ("Missing prefix!")
End If
' check if all inputs are ok
If inputFileOk And inputSplitOk And prefixOk Then
cancelActive = False
Unload Me
End If
End Sub
'---------------------------------------------------------------------------
' CANCEL BUTTON
'---------------------------------------------------------------------------
Private Sub CancelButton_Click()
cancelActive = True ' for script termination
Unload Me
End Sub
'---------------------------------------------------------------------------
' FILE BUTTON
'---------------------------------------------------------------------------
Private Sub FileButton_Click()
Dim i As Integer ' file selection index
' show file chooser dialog and assign selected file to sFileName
Application.FileDialog(msoFileDialogOpen).AllowMultiSelect = False
i = Application.FileDialog(msoFileDialogOpen).Show
If i <> 0 Then
sFileName = Application.FileDialog(msoFileDialogOpen).SelectedItems(1)
FileTxtBox.Text = sFileName
End If
End Sub