Добавьте возврат каретки в Powershell, чтобы вручную распечатать большой файл XML - PullRequest
1 голос
/ 12 марта 2019

У меня есть действительно большой (280 Мегабайт) XML-файл, который находится в одной строке.У меня есть несколько редакторов, которые могут едва справиться с открытием, но ничто не позволит мне его распечатать.

Я пытаюсь отформатировать его в Powershell, но не смогвыяснить синтаксис.Чтобы сделать файл более читабельным, я бы хотел заменить все закрывающие теги на возврат каретки + перевод строки и закрывающий тег, но я не смог заставить его работать.

Вот что я пробовал до сих пор:

(get-content .\ReallyHugeXMLFile2.xml) -replace ('</','`n</') | out-file .\ReallyHugeXMLFile2Formatted.xml
(get-content .\ReallyHugeXMLFile2.xml) -replace ('</','\r\n</') | out-file .\ReallyHugeXMLFile2Formatted2.xml
(get-content .\ReallyHugeXMLFile2.xml) -replace ('</','\\r\\n</') | out-file .\ReallyHugeXMLFile2Formatted3.xml

Спасибо

1 Ответ

2 голосов
/ 12 марта 2019

TheIncorrigible1 предоставил критический указатель в комментарии:

Предполагая, что ваш большой XML-файл все еще может быть загружен в System.Xml.XmlDocument экземпляр в целом , вы можете просто вызвать его метод .Save() для создания выходного файла Pretty-Printed (который устраняет необходимость ручной вставки новой строки; плюс, использование парсера XMLвсегда предпочтительнее, чем манипулирование текстом).

# Load the file into a [xml] (System.Xml.XmlDocument) instance...
($xmlDoc = New-Object xml).Load($PWD.ProviderPath + '/HugeFile.xml')
# ... and save it, which automatically pretty-prints it.
$xmlDoc.Save($PWD.ProviderPath + '/HugeFilePrettyPrinted.xml')

Обратите внимание на необходимость добавить $PWD.ProviderPath к именам файлов, чтобы убедиться, что .NET использует текущий каталог PowerShell (обычно .NET отличается, а .NET не делает)t знать о дисках PowerShell, созданных с помощью New-PSDrive). [1]

Примечание. Полученный файл будет содержать только новые строки LF, а не CRLF.


A технико-экономическое обоснование :

Сначала запустите следующий код (PSv5 +), чтобы создать образец XML-файла , размер которого составляет около 280 МБ.Обратите внимание, что вы можете легко настроить код для указания другого целевого размера.

Примечание:

  • Файл HugeFile.xml будет создан в текущем каталоге и запуститсяКоманда pretty-printing позже создает (еще больше) HugeFilePrettyPrinted.xml в том же месте.

  • Создание этого файла может занять несколько минут.

# Create a sample single-line XML file of a given size (approximately).
# Note: Depending on the target size, this can take a long time to complete.
#       Additionally, for performance reasons the code is written so that
#       the file content must fit into memory as a whole.

# The desired size of the resulting file.
$targetFileSize = 280mb
$targetFile = './HugeFile.xml'

# The XML element to repeat.
$repeatingElementTemplate = '<book><title>De Profundis {0:000000000000}</title></book>'
# Determine how often it must be repeated to reach the target size (approximately)
$repeatCount = $targetFileSize / ($repeatingElementTemplate.Length - 4)

Write-Verbose -vb "Creating XML file '$targetFile' of approximate size $('{0:N2}' -f ($targetFileSize / 1mb)) MB..."
# Create the file.
'<?xml version="1.0"?><catalog>' | Set-Content -NoNewline -Encoding Utf8 $targetFile
-join (1..$repeatCount).ForEach({ $repeatingElementTemplate -f $_ }) |
  Add-Content -NoNewline -Encoding Utf8 $targetFile
'</catalog>' | Add-Content -NoNewline -Encoding Utf8 $targetFile

Затем выполните команду pretty-printing выше.

На моей одноядерной виртуальной машине Windows 10 с 3 ГБ ОЗУ (на старом оборудовании) это заняло около 40 секунд.Сам Эрик сообщает о своем компьютере менее чем за 5 секунд.


[1] Обеспечение правильной передачи относительного пути файловой системы PowerShell в метод .NET :

  • Как уже говорилось, представление текущего каталога в .NET обычно отличается от представления PowerShell, поэтому относительные пути PowerShell нельзя использовать как есть.

  • Формирование полногопуть с $PWD.ProviderPath ($PWD.ProviderPath + '<fileInCurrentDir>) гарантирует, что текущее местоположение файловой системы PowerShell выражается как собственный путь к файловой системе (спасибо, TheIncorrigible1).Методы .NET понимают только последнее;они не знают о пользовательских дисках PowerShell, созданных с помощью New-PSDrive, и не знают нотацию с префиксом поставщика PowerShell, которая $PWD соответствует тому, когда текущим местоположением является путь UNC (например,
    Microsoft.PowerShell.Core\FileSystem::\\some-server\some-share\some-folder).

  • Если вы не используете собственные диски PowerShell и не запускаете свой код непосредственно из UNC-местоположений, вы можете проще построить полный путь на основе текущего местоположенияс
    "$PWD/<fileInCurrentDir>".

  • И наоборот, для полная надежность вам придется использовать
    (Get-Location -PSProvider FileSystem).ProviderPath + '/<fileInCurrentDir>', учитывая, что текущее местоположение PowerShell может быть одним из от поставщика другой , чем поставщик файловой системы;например, HKCU:\Console (поставщик реестра).

...