VBA XMLHTTP Состояние «Недостаточно памяти» - PullRequest
0 голосов
/ 06 декабря 2018

Вот фрагмент кода, который должен подключаться к веб-странице со следующим содержанием: link1, description1, otherdata1, link2, description2, otherdata2, ..., linkN, descriptionN, otherdataN, где N равно 30 000 +.

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

Моя проблема заключается в следующем: на htmlWebInterfaceXML.send часто, но не всегда, программе не хватает памяти (ошибка «недостаточно памяти»).Мне трудно тестировать разные решения, потому что обычно программа работает без сбоев, и трудно заметить изменения, если таковые имеются.

Дополнительная информация:

  • На некоторых компьютерах он работает без сбоев и не работает на других
  • Обычно работает до полудня и выдает ошибку, затем

Другие полезные сведения:

  • приведенный код является частным методом класса, а сам класс является небольшой частью исходного кода
  • другие подпрограммыВызовы, которые я не объясняю, не актуальны и работают без сбоев, проблема всегда появляется в htmlWebInterfaceXML.send.

Одно из моих предположений состоит в том, что я объявил локальную переменную внутри функции, которая содержит очень большой объект и может вызвать переполнение стека, но это маловероятно, поскольку VBA должен справиться с этими задачами самостоятельно. Может быть, вы видите проблему, которую я не вижу? Спасибо.

Private Sub FileUpload()
    ' THE FUNCTION CANNOT BE CONNECTING FOR EACH CONTRACT ID! WILL TAKE TOO MUCH TIME - NEED TO ALTER
    Dim member As Variant
    Dim byteCounter As Byte
    Dim byteMaxID As Byte
    Dim strPathToXMLFile As String
    Dim strURLToXMLFile    
    Dim strXMLFileStorageName As String    
    Dim domdocXMLText As New MSXML2.DOMDocument
    Dim clctStrFoundMatches As New Collection
    Dim clctInternalIDs As New Collection
    Dim vrntContractID As Variant
    Dim htmlHTMLMainPageXMLInterface As New MSHTML.HTMLDocument
    Dim htmlTagElement As Variant
    Dim htmclctFoundXMLs As MSHTML.IHTMLElementCollection
    Dim htmlWebInterfaceXML As MSXML2.XMLHTTP60
    Dim intNumberOfTradeUnderProcessing As Integer

    UpdateProgressStatus "LOADING SERVER WITH SOURCE XML..." '<----------- UPDATE PROGRESS!


    '----------------------> OPEN AND LOAD THE WEB SERVER, AND STORE ITS HTML INTO AN OBJECT
    Set htmlWebInterfaceXML = New MSXML2.XMLHTTP
    With htmlWebInterfaceXML
        .Open "GET", p_cstrWebInterfaceXMLRootDirectory, False
        .setRequestHeader "Authorization", "Basic" & Base64Encode( _
                                          p_cstrXMLWebInterfaceAuthenticationUser & ":" & p_cstrXMLWebInterfaceAuthenticationPassword)
        .setRequestHeader "Pragma", "no-cache"
        .setRequestHeader "Cache-Control", "no-cache"
        .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
        .send
    End With
    htmlHTMLMainPageXMLInterface.body.innerHTML = htmlWebInterfaceXML.responseText ' how much text is the htmldocument able to store??
    Set htmlWebInterfaceXML = Nothing

    SetUpDirectory                               ' ------------> create or set directory where to store XML files

    If Me.ContractiDs.Count <> Me.MailParts.Count And Me.ContractiDs.Count <> Me.MailParts.Count * 2 Then
        Err.Raise 1504, "FileUpload", p_cstrError1504Message
    Else
        For Each vrntContractID In Me.ContractiDs

            intNumberOfTradeUnderProcessing = intNumberOfTradeUnderProcessing + 1
            UpdateProgressStatus "LOADING XML FOR THE TRADE NUMBER " & intNumberOfTradeUnderProcessing & "..." ' ----------------> UPDATE STATUS BAR

            ' ------------------------> find the tags containing the needed contract id in their names

            Set htmclctFoundXMLs = htmlHTMLMainPageXMLInterface.getElementsByTagName("a")
            Set clctStrFoundMatches = New Collection
            For Each htmlTagElement In htmclctFoundXMLs
                If htmlTagElement.getAttribute("href") Like "*" & vrntContractID & "*" Then
                    clctStrFoundMatches.Add htmlTagElement
                End If
            Next htmlTagElement

            If clctStrFoundMatches.Count = 0 Then Err.Raise 1506, "FileUpload", p_cstrError1506Message

            ' -----------------------> exclude the archives from the collection

            byteCounter = 0
            For byteCounter = 1 To clctStrFoundMatches.Count
                If blnContainsPattern("\.gz$", clctStrFoundMatches(byteCounter).innerText) Then
                    clctStrFoundMatches.Remove byteCounter
                End If
            Next byteCounter

            ' ----------------------> extract the contract ids and find the last contract id

            Set clctInternalIDs = New Collection

            For Each member In clctStrFoundMatches
                clctInternalIDs.Add strReturnSingleMatch("\d{9}", member.innerText)
                If clctInternalIDs(clctInternalIDs.Count) = "False" Then Err.Raise 1505, "FileUpload", p_cstrError1505Message
            Next member
            byteMaxID = FindMaximum(clctInternalIDs)
            strPathToXMLFile = clctStrFoundMatches(byteMaxID).innerText

            ' -----------------------> check whether such file exists, and, if not, download it

            If blnFileExists(strPathToXMLFile, p_cstrXMLDestination) Then
            Else
                strURLToXMLFile = p_cstrWebInterfaceXMLRootDirectory & strPathToXMLFile
                Set htmlWebInterfaceXML = Nothing: Set htmlWebInterfaceXML = New MSXML2.XMLHTTP
                htmlWebInterfaceXML.Open "GET", strURLToXMLFile, False
                htmlWebInterfaceXML.setRequestHeader "Authorization", "Basic" & Base64Encode( _
                                                                     p_cstrXMLWebInterfaceAuthenticationUser & ":" & p_cstrXMLWebIntervaceAuthenticationPassword)
                htmlWebInterfaceXML.send
                With domdocXMLText
                    .validateOnParse = False
                    .async = False
                End With
                domdocXMLText.LoadXML htmlWebInterfaceXML.responseText
                domdocXMLText.Save p_cstrXMLDestination & "\" & strPathToXMLFile
            End If
        Next vrntContractID

    End If

    Set htmlHTMLMainPageXMLInterface = Nothing

End Sub

1 Ответ

0 голосов
/ 16 августа 2019

У меня была похожая проблема, которую я решил.Мой сценарий прошел через сервер и искал строку в тысячах текстовых файлов.

Способ, которым я решил это (используя ascync ServerXMLHTTP60), задает условие if в обработчике ответа для ABORT объекта xmlhttp.После того как я закончил сравнивать данные, объект «выпал» из памяти, и теперь я могу (практически) запрашивать любой объем данных.(у меня ушло около месяца, чтобы протестировать множество решений, и это было правильное решение)

Это может работать для вас, поэтому просто добавьте htmlWebInterfaceXML.abort после того, как вы закончите с этим набором данных.

Надеюсь, это поможет!Ура!

...