Class 基于 streamReader 和 xmlReader 锁定文件,函数不

Class based streamReader & xmlReader locks files, function doesn't

我正在将一些基于函数的 XML reader 代码重构为 class 方法,并发现了一些问题。使用该函数,我可以 运行 测试并验证 XML 加载是否正确,然后更改 XML 并测试错误情况。但是这种基于 class 的方法由于 "the file is open in another program" 而失败,迫使我在修改 XML 之前关闭控制台。 最初我直接在 xmlReader 中使用路径。所以我移动到一个 StreamReader 输入到 xmlReader。我什至尝试创建一个全新的 xmlDocument,并将加载的 XML 的根节点导入到那个新的 xmlDocument 中。 None 有效。 我怀疑基于函数的版本起作用的原因是因为 xmlReader 变量是本地范围,所以当函数完成时它超出了范围。但我正在抓住那里的救命稻草。我还读到垃圾收集可能是一个问题,所以我在 Dispose 之后添加了 [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,FileShare 是 ReadWrite,就像这样

$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

仍然没有运气。

我认为您在 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()

然后它应该可以释放文件锁。