Цикл по большому файлу XML - PullRequest
       6

Цикл по большому файлу XML

6 голосов
/ 14 февраля 2011

У меня проблемы с циклическим перезаписыванием XML-файла размером около 20-30 МБ (650000 строк).

Это мой метакод:

<cffile action="READ" ile="file.xml" variable="usersRaw">

<cfset usersXML = XmlParse(usersRaw)>
<cfset advsXML = XmlSearch(usersXML, "/advs/advuser")>
<cfset users = XmlSearch(usersXML, "/advs/advuser/user")>

<cfset numUsers = ArrayLen(users)>
<cfloop index="i" from="1" to="#numUsers#">
    ... some selects...
    ... insert...
    <cfset advs = annunciXml[i]["vehicle"]>
    <cfset numAdvs = ArrayLen(advs)> 
    <cfloop index="k" from="1" to="#numAdvs#">        
        ... insert... or ... update...
    </cfloop>
</cfloop>

(да, не очень хорошо: -)

<advs>
   <advuser>
      <user>
      </user>
      <vehicle>
      <vehicle>
   </advuser>
</advs>

После ~ 120 000 строк я получаю сообщение об ошибке: «Недостаточно памяти».

Как улучшить производительность моего скрипта?

Как я могу диагностировать, где есть максимальное потребление памяти?

Ответы [ 4 ]

10 голосов
/ 14 февраля 2011

@ SamG правильно, что синтаксический анализ ColdFusion XML не может сделать это из-за парсера DOM, но SAX болезненен, вместо этого используйте парсер StAX, который предоставляет гораздо более простой интерфейс итератора. См. Ответ на другой вопрос, который я предоставил, для примера того, как сделать это с ColdFusion .

Это примерно то, что вы бы сделали для своего примера:

<cfset fis = createObject("java", "java.io.FileInputStream").init(
    "#getDirectoryFromPath(getCurrentTemplatePath())#/file.xml"
)>
<cfset bis = createObject("java", "java.io.BufferedInputStream").init(fis)>
<cfset XMLInputFactory = createObject("java", "javax.xml.stream.XMLInputFactory").newInstance()>
<cfset reader = XMLInputFactory.createXMLStreamReader(bis)>

<cfloop condition="#reader.hasNext()#">
    <cfset event = reader.next()>
    <cfif event EQ reader.START_ELEMENT>
        <cfswitch expression="#reader.getLocalName()#">
            <cfcase value="advs">
                <!--- root node, do nothing --->
            </cfcase>
            <cfcase value="advuser">
                <!--- set values used later on for inserts, selects, updates --->
            </cfcase>
            <cfcase value="user">
                <!--- some selects and insert --->
            </cfcase>
            <cfcase value="vehicle">
                <!--- insert or update --->
            </cfcase>
        </cfswitch>
    </cfif>
</cfloop>

<cfset reader.close()>
2 голосов
/ 11 мая 2011

апельсины обеспечивают разумное решение.Пожалуйста, взгляните на решение Бена Наделя для обработки очень больших файлов XML в ColdFusion.Я проверил его подход на 50-мегабайтном XML-файле с 1,2 миллионами строк.Бен использует похожий подход, который здесь представлен в Orangepips - потоковая передача с использованием Java, затем XMLParse для каждого узла в ColdFusion, чтобы добраться до товаров.Проверьте это - как и большинство кода и руководств Бена Наделя, он просто работает.

http://www.bennadel.com/blog/1345-Ask-Ben-Parsing-Very-Large-XML-Documents-In-ColdFusion.htm

1 голос
/ 15 февраля 2011

Я не знаю ColdFusion, но 20-30 МБ не выходят за рамки технологий, которые строят дерево в памяти;многие люди регулярно используют XSLT-преобразования для файлов размером 200 МБ.

Переход на синтаксический анализ SAX звучит как крайняя мера - это такой низкоуровневый интерфейс.

1 голос
/ 14 февраля 2011

Я полагаю, что синтаксический анализатор Cold Fusion XML использует синтаксический анализ DOM, который не подходит для файлов такого размера. Вы должны попытаться найти парсер SAX, который управляется событиями. Может быть, эта ссылка поможет http://coldfusion.sys -con.com / узел / 236002

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...