Оптимизация vbscript: как ускорить запись файлов

Ниже приводится обычная функция журнала, которую я использую во многих своих сценариях vbscripts, которые я соответствующим образом изменяю. Мне кажется, он пишет слишком медленно. У меня 3 вопроса:

  1. Есть идеи, как оптимизировать это, чтобы он писал быстрее?
  2. Было бы быстрее сначала сохранить весь текст в строке, а затем запустить функцию OutputToLog, или было бы быстрее выполнять OutputToLog каждый раз, когда мне нужно было вставить строку в текстовый файл?
  3. Если место на диске не имело значения, возможно ли, что во время записи в текстовый файл во время выполнения закончится нехватка памяти ... что приведет к тому, что сценарий будет выполняться все медленнее и медленнее?

Вот моя функция vbscript

Function OutputToLog (strToAdd)  
    Dim strDirectory,strFile,strText, objFile,objFolder,objTextFile,objFSO
    strDirectory = "c:\log"
    strFile = "\log-"& StampNow &  ".bat"
    'strText = "test"
    strText = strToAdd

    ' Create the File System Object
    Set objFSO = CreateObject("Scripting.FileSystemObject")

    ' Check that the strDirectory folder exists
    If objFSO.FolderExists(strDirectory) Then
       Set objFolder = objFSO.GetFolder(strDirectory)
    Else
       Set objFolder = objFSO.CreateFolder(strDirectory)
       'WScript.Echo "Just created " & strDirectory
    End If

    If objFSO.FileExists(strDirectory & strFile) Then
       Set objFolder = objFSO.GetFolder(strDirectory)
    Else
       Set objFile = objFSO.CreateTextFile(strDirectory & strFile)
       'Wscript.Echo "Just created " & strDirectory & strFile
    End If

    set objFile = nothing
    set objFolder = nothing
    ' OpenTextFile Method needs a Const value
    ' ForAppending = 8 ForReading = 1, ForWriting = 2
    Const ForAppending = 8

    Set objTextFile = objFSO.OpenTextFile _
    (strDirectory & strFile, ForAppending, True)

    ' Writes strText every time you run this VBScript
    objTextFile.WriteLine(strText)
    objTextFile.Close
End Function

заранее спасибо


person phill    schedule 27.01.2009    source источник
comment
Вам не нужно проверять, существует ли файл, OpenTextFile создаст файл, если он не существует, если True передается в качестве третьего параметра. Это может не сэкономить много времени, но сэкономит часть набора текста.   -  person Tester101    schedule 27.01.2009


Ответы (4)


Я думаю, вы захотите как создать свои объекты FSO, так и открыть файл журнала за пределами функции OutputToLog. Это может не сэкономить много времени, но зачем создавать объекты, открывать и закрывать файлы при каждой записи?

В противном случае, если вы хотите сохранить функции как есть, выполнение только одной записи должно быть быстрее.

person Scott Hoffman    schedule 02.02.2009
comment
+1 Открытие / сканирование / закрытие - самые экономичные операции для окон, так что ваше место. Также код выглядит так, как будто он может использовать монопольный доступ, оставив в использовании. - person Martijn Laarman; 02.02.2009
comment
На самом деле это противоположность тому, что говорит Мартейн. Открытие, добавление и закрытие - это операции, которые Windows всегда была чрезвычайно быстрой, начиная с Windows NT. Даже система начального уровня может легко открыть файл журнала, добавить в него строку текста и снова закрыть ее 100–200 раз в секунду, без заметного замедления по мере роста файла. Моя текущая система делает это примерно за 4 мс за цикл при записи на жесткий диск или за 3 мс при записи на SSD. - person Luc VdV; 15.01.2018
comment
Просто чтобы прояснить - мой предыдущий комментарий не означает, что вы не улучшите время выполнения за счет оптимизации кода. Я имею в виду, что операции открытия / добавления / закрытия выполняются намного быстрее, чем можно было бы ожидать от большинства затрат, поэтому выигрыш в скорости не так велик. Я бы сделал противоположное тому, что было предложено, хотя бы для того, чтобы убедиться, что мой файл журнала может быть исследован в любое время, в том числе во время выполнения, и что он сохраняется со всем своим содержимым, если приложение выйдет из строя или будет убито, не позволяя ему аккуратно закройте файл. - person Luc VdV; 15.01.2018

Если вы выполняете много небольших операций записи, вам немного поможет рефакторинг проверок на наличие FolderExists и FileExists. Может быть, попытаться записать в файл, перехватывая любые ошибки, и проверить FolderExists и FileExists в обработчике ошибок и создать их, если необходимо?

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

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

Поскольку вы добавляете файл, чем дольше становится файл журнала, тем больше времени занимает запись, потому что (AFAIK) весь файл должен каждый раз перезаписываться. Это еще одна причина, по которой нужно реже писать длинные строки.

Могли бы вы вместо этого использовать журнал событий Windows?

person gkrogers    schedule 27.01.2009
comment
не будет ли быстрее создавать файлы меньшего размера, а затем объединять их все в конце процесса? - person phill; 27.01.2009
comment
Я не могу использовать журнал событий, потому что я использую файл журнала для создания командного файла для последующего запуска. В одном случае я обнаружил, что проще создать и затем выполнить пакетный файл команд xcopy, чем использовать объект copyfile в vbscript. - person phill; 27.01.2009
comment
Я просто изменил сценарий, чтобы сохранить все в строке перед выполнением указанной выше функции. Похоже, что сейчас он идет быстрее. Думаю, мы действительно увидим, что произойдет в ближайшие 2 часа или около того. Он должен просеять 50 гигабайт файлов и папок перед выводом в файл. - person phill; 28.01.2009
comment
Сама запись - не самая экономичная операция. Открытие / сканирование (даже eof) / закрытие файла обычно замедляет доступ к файлу. - person Martijn Laarman; 02.02.2009

Все ваши папки / файлы проверяются и создаются один раз в функции подготовки, а затем вы можете просто добавить в файл журнала, зная, что он будет там? Кроме того, вы должны иметь возможность просто создать объект fso один раз.

Что-то вроде следующего (непроверенный код)

Dim loggerFSO

Function PrepLog
    dim objFolder
    ' Create the File System Object
    if loggerFSO is nothing then Set loggerFSO = CreateObject("Scripting.FileSystemObject")

    ' Check that the strDirectory folder exists
    If loggerFSO.FolderExists(strDirectory) Then
       Set objFolder = loggerFSO.GetFolder(strDirectory)
    Else
       Set objFolder = loggerFSO.CreateFolder(strDirectory)
       'WScript.Echo "Just created " & strDirectory
    End If

    If loggerFSO.FileExists(strDirectory & strFile) Then
       ' do nothing
    Else
       loggerFSO.CreateTextFile(strDirectory & strFile)
       'Wscript.Echo "Just created " & strDirectory & strFile
    End If
End function

Function OutputToLog (strToAdd)  
    Dim strDirectory,strFile,strText, objTextFile
    strDirectory = "c:\log"
    strFile = "\log-"& StampNow &  ".bat"
    'strText = "test"
    strText = strToAdd

    ' Create the File System Object
    if loggerFSO is nothing then Set loggerFSO = CreateObject("Scripting.FileSystemObject")

    ' OpenTextFile Method needs a Const value
    ' ForAppending = 8 ForReading = 1, ForWriting = 2
    Const ForAppending = 8

    Set objTextFile = loggerFSO.OpenTextFile _
    (strDirectory & strFile, ForAppending, True)

    ' Writes strText every time you run this VBScript
    objTextFile.WriteLine(strText)
    objTextFile.Close
End Function
person Binary Worrier    schedule 27.01.2009

Не закрывайте файл между вызовами, пусть объект textstream позаботится о закрытии, когда он завершится.

Dim OutputToLogFileObject
Function OutputToLog (strToAdd)  
    Dim strDirectory,strFile,strText, objFile,objFolder,objTextFile,objFSO
    If IsEmpty(OutputToLogFileObject) Then
        strDirectory = "c:\log"
        strFile = "\log-"& StampNow &  ".bat"
        'strText = "test"
        strText = strToAdd

        ' Create the File System Object
        Set objFSO = CreateObject("Scripting.FileSystemObject")

        ' Check that the strDirectory folder exists
        If objFSO.FolderExists(strDirectory) Then
           Set objFolder = objFSO.GetFolder(strDirectory)
        Else
           Set objFolder = objFSO.CreateFolder(strDirectory)
           'WScript.Echo "Just created " & strDirectory
        End If

        If objFSO.FileExists(strDirectory & strFile) Then
           Set objFolder = objFSO.GetFolder(strDirectory)
        Else
           Set objFile = objFSO.CreateTextFile(strDirectory & strFile)
           'Wscript.Echo "Just created " & strDirectory & strFile
        End If

        set objFile = nothing
        set objFolder = nothing
        ' OpenTextFile Method needs a Const value
        ' ForAppending = 8 ForReading = 1, ForWriting = 2
        Const ForAppending = 8

        Set OutputToLogFileObject = objFSO.OpenTextFile _
        (strDirectory & strFile, ForAppending, True)
    End If
    OutputToLogFileObject.WriteLine strText
 End Function
person svinto    schedule 02.02.2009