StreamReader и xmlReader на основе классов блокируют файлы, функция не - PullRequest
0 голосов
/ 08 ноября 2019

Я выполняю рефакторинг кода функции чтения XML на основе методов класса и вижу некоторые проблемы. С помощью этой функции я могу запустить тест и проверить правильность загруженного XML, затем изменить XML и проверить наличие ошибок. Но этот подход на основе классов терпит неудачу из-за того, что «файл открыт в другой программе», заставляя меня закрыть консоль, прежде чем я смогу пересмотреть XML. Первоначально я использовал путь непосредственно в xmlReader. Поэтому я перешел на вход StreamReader в xmlReader. И я даже поиграл с созданием нового xmlDocument и импортом корневого узла загруженного XML в этот новый xmlDocument. Ни один не работает. Я подозреваю, что причина работы версии, основанной на функции, заключается в том, что переменная xmlReader является локальной областью действия, поэтому она выходит из области действия после завершения функции. Но я цепляюсь за соломинку там. Я также читал, что сборка мусора может быть проблемой, поэтому я добавил [system.gc]::Collect() сразу после удаления и все еще без изменений.

class ImportXML {
    # Properties
    [int]$status = 0
    [xml.xmlDocument]$xml = ([xml.xmlDocument]::New())
    [collections.arrayList]$message = ([collections.arrayList]::New())

    # Methods
    [xml.xmlDocument] ImportFile([string]$path) {
        $importError = $false
        $importFile = ([xml.xmlDocument]::New())
        $xmlReaderSettings = [xml.xmlReaderSettings]::New()
        $xmlReaderSettings.ignoreComments = $true
        $xmlReaderSettings.closeInput = $true
        $xmlReaderSettings.prohibitDtd = $false
        try {
            $streamReader = [io.streamReader]::New($path)
            $xmlreader = [xml.xmlreader]::Create($streamReader, $xmlReaderSettings)
            [void]$importFile.Load($xmlreader)
            $xmlreader.Dispose
            $streamReader.Dispose
        } catch {
            $exceptionName = $_.exception.GetType().name
            $exceptionMessage = $_.exception.message
            switch ($exceptionName) {
                Default {
                    [void]$this.message.Add("E_$($exceptionName): $exceptionMessage")
                    $importError = $true
                }
            }
        }

        if ($importError) {
            $importFile = $null
        }

        return $importFile
    }
}

class SettingsXML : ImportXML {
    # Constructor
    SettingsXML([string]$path){
        if ($this.xml = $this.ImportFile($path)) {
            Write-Host "$path!"
        } else {
            Write-Host "$($this.message)"
        }
    }
}

$settingsPath = '\\Mac\iCloud Drive\Px Tools\Dev 4.0\Settings.xml'
$settings = [SettingsXML]::New($settingsPath)

РЕДАКТИРОВАТЬ: я также попытался FileStream, а не StreamReader, с FileShareReadWrite, вот так

$fileMode = [System.IO.FileMode]::Open
$fileAccess = [System.IO.FileAccess]::Read
$fileShare = [System.IO.FileShare]::ReadWrite
$fileStream = New-Object -TypeName System.IO.FileStream $path, $fileMode, $fileAccess, $fileShare

Все еще не повезло.

1 Ответ

2 голосов
/ 08 ноября 2019

Я думаю, что вы находитесь на правильной линии с Dispose, но на самом деле вы не вызываете метод - вы просто получаете ссылку на него, а затем ничего не делаете с ним. ..

Сравните:

PS> $streamReader = [io.streamReader]::New(".\test.xml");
PS> $streamReader.Dispose

OverloadDefinitions
-------------------
void Dispose()
void IDisposable.Dispose()
PS> _

с

PS> $streamReader = [io.streamReader]::New(".\test.xml");
PS> $streamReader.Dispose()
PS> _

Вам нужно добавить немного () после имени метода, чтобы ваш код стал:

$xmlreader.Dispose()
$streamReader.Dispose()

И тогда он должен снять блокировку файла.

...