簡體   English   中英

PowerShell:腳本無法打開存檔中的本機文件,但能夠打開新創建的文件

[英]PowerShell : Script unable to open native file in archive, but able for newly created file

嗨,大家好 !

我創建了一個 powershell 腳本,它通過一些存檔文件在其中一個文件中進行一些簡單的文本編輯。

我的問題很簡單,當我想打開和編輯 xxx.ini 時,它失敗了。 然而,當我添加一個 test.ini (或刪除 xxx.ini,然后將其重新添加)並嘗試在這個新文件上運行完全相同的腳本時,它就可以工作了。

我嘗試查找IsReadOnly屬性,但它返回 false。

有人能幫忙嗎?

        if ($f -notmatch "bulkPrefEditor"){
            # The zip file to be updated
            $file = $f

            # Is the file read only ? Let's try to force that to false
            $isReadOnly = Get-ItemProperty -Path $file | Select-Object IsReadOnly
            Write-Log "Is $file Read-Only : $isReadOnly" "INFO" $logfile
            Set-ItemProperty -Path $file -Name IsReadOnly -Value $false


            Write-Log "Editing following file : $f" "INFO" $logfile

            # Load ZipFile (Compression.FileSystem) if necessary
            try { $null = [IO.Compression.ZipFile] }
            catch { [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') }

            # Open zip file with update mode (Update, Read, Create -- are the options)
            try { 
                $fileZip = [System.IO.Compression.ZipFile]::Open( $file, 'Update' )
            }
            catch {
                Write-Log "Another process has locked the '$file' file." "ERROR" $logfile
                Write-Log "Another process has locked the '$file' file."
                continue
            }

            # Finding the specific file within the zip file
            try{
                $fileZip.Entries | Where-Object { $_.FullName -match "$innerpath" }
            } catch {
                Write-Log "Could not find $filepath\$innerpath in $f , have you used anti-slash instead of slash ?" "WARN" $logfile
                Write-Log "Could not find $filepath\$innerpath in $f , have you used anti-slash instead of slash "
                continue
            }
            pause
            # If needed, read the contents of specific file to $text and release the file so to use streamwriter later
            try{
                $desiredFile = [System.IO.StreamReader]($fileZip.Entries | Where-Object { $_.FullName -match "$innerpath" }).Open()
                $text = $desiredFile.ReadToEnd()
                $desiredFile.Close()
                $desiredFile.Dispose()
            }
            catch {
                Write-Log "Could not read $f/$innerpath in $f " "WARN" $logfile
                Write-Log "Could not read $f/$innerpath in $f "
                continue
            }

結果: 在此處輸入圖像描述

我在腳本中添加了一些簡單的日志:

2019/11/21 18:40:12 INFO ################### 啟動腳本... ############## ###### 2019/11/21 18:40:12 INFO 此腳本將對 C:\Users\pfournet\Documents\Factory\BulkPrefEditor 中包含的文件進行操作 2019/11/21 18:40:12 INFO 此腳本可以看到(4)個文件。 2019/11/21 18:40:12 INFO List of available files (single line): 20191119-123448387 - Copie (2).zip 20191119-123448387 - Copie.zip 20191119-123448387.zip BulkPrefEditor.ps1 BulkPrefEditor_Zip.ps1 2019/ 11/21 18:40:12信息已找到此文件:20191119-123448387 -Copie(2).zip 2019/2021/21/21/21/21/21 18:40:12 INFO THIN222221B. 2011BIE:20191119-119-123488888888888888884888484848484848484848484848484848484848484848484848484848488848 lar /11/21 18:40:12 INFO 此文件已找到:20191119-123448387.zip 2019/11/21 18:40:12 INFO 此腳本將替換此行:use-compression = true 與 use-compression = false 2019/11/21 18:40:12 INFO ################### 開始運營################ ### 2019/11/21 18:40:12 INFO 是 20191119-123448387 - 副本 (2).zip 只讀:@{IsReadOnly=False} 2019/11/21 18:40:12 INFO 編輯以下文件: 2 0191119-123448387 - 復制 (2).zip 2019/11/21 18:40:13 警告無法讀取 20191119-123448387 - 復制 (2).zip/ul-flow/plugins/19-191.ini in 24481721 (2)。 -123448387 - Copie.zip 2019/11/21 18:40:13 WARN Could not read 20191119-123448387 - Copie.zip/ul-flow/plugins/interactivedata.ini in 20191119-123448387 - Copie.zip 2019/11/21 18:40:13 INFO Is 20191119-123448387.zip Read-Only: @{IsReadOnly=False} 2019/11/21 18:40:13 INFO Editing following file: 20191119-123448387.zip 2019/11/21 18:40 :14 WARN 無法讀取 20191119-123448387.ZADCDBD79A8D84 中的 20191119-123448387.zip/ul-flow/plugins/interactivedata.ini 175C229B192AADC02F2Z 2019/11/21 18:40:14 信息 #################### 結束腳本... ############# #######

正如 Rich Moss 在他們的評論中提到的那樣,您編寫的腳本不會處理對象,並且您正在鎖定 zip 文件。 我最初的解決方案是從存檔中提取所有文件,修改您需要的文件,然后重新壓縮。

Add-Type -AssemblyName System.IO.Compression.FileSystem

$file = Get-ChildItem C:\temp\test3.zip

$tempOutputFolder = "c:\temp\$(New-Guid)"

[System.IO.Compression.ZipFile]::ExtractToDirectory($file.FullName, $tempOutputFolder)

$zippedFilesToEdit = Get-ChildItem $tempOutputFolder -Recurse -File | Where-Object { $_.Name -eq "new 1" }

foreach ($zippedFile in $zippedFilesToEdit){
    #Modifiy your file, and save it
    Get-Content $zippedFile | for-each {$_ -replace "Pattern","ReplaceWith"} | Out-File $zippedFile.FullName
}

Remove-Item $file.FullName
[System.IO.Compression.ZipFile]::CreateFromDirectory($tempOutputFolder,$file.FullName)

這不如直接從存檔中修改文件 object 靈活。 如果你有一個很大的存檔/文件,這將花費太長時間,所以我坐下來通過 stream 來完成它。 該腳本有效,但我相信可能會有改進。 (我認為我們實際上可以直接編輯 stream)此外,錯誤處理可能會更好。 我們希望確保在失敗完成時關閉/處理所有對象,因此我們需要一個 try/catch/finally 塊圍繞整個事物,這需要我們檢查單個錯誤,重新打包並拋出(`Write- Error -ErrorAction Stop) 再次。 這會使調試更加困難,因為您不會看到錯誤的實際行號。 您必須確保在捕獲錯誤時正確處理預期和意外錯誤。

這適用於我在 Win 10/PS 5.1 上運行。

編輯我在開頭和結尾添加了代碼,它將通過創建一個包含 10 個生成文件的 zip 存檔來測試這一點,報告大小,然后執行編輯操作並解壓縮以檢查修改文件的大小。 此代碼將從 $Test* 位置刪除文件。 在運行之前閱讀腳本,以便在按下 F5 之前知道它會做什么

$TestPath = "C:\temp\zipTest"
$testZipPath = "C:\temp\ZipTest.zip"
$filePathToFind = "test 1.txt"

If (-not (Test-Path $TestPath)){New-Item -Path $TestPath -ItemType Directory}
foreach( $i in 1..10){
   "Some Text/file contents" | Set-Content -Path "$TestPath\test $i.txt" 
}
Remove-Item -Path $testZipPath -Force -ErrorAction SilentlyContinue | Out-Null
[System.IO.Compression.ZipFile]::CreateFromDirectory($TestPath,$testZipPath)

Write-Host "File sizes before any operation: "
Get-ChildItem $testZipPath | foreach { Write-Host "filename: $($_.Name), length: $($_.Length)"}
Write-Host "test zip file size: $(Get-ChildItem $testZipPath | select -ExpandProperty Length)"

$file = $testZipPath
Write-Host ""
Write-Host "Running the opertion to modify the file in the archive"
try{

    # Check if zip files exists, and can open the file, then open if possible
    If(-not (Test-Path $file)){Write-Error "Zip File does not exist" -ErrorAction Stop}
    try { $fileZip = [System.IO.Compression.ZipFile]::Open( $file, 'Update' ) }
    catch { Write-Error "Another process has locked the '$file' file." -ErrorAction Stop }

    # Finding the specific file within the zip file
    try{ $fileZip.Entries | Where-Object { $_.FullName -eq $filePathToFind } | Out-Null} 
    catch { Write-Error "Could not find $filePathToFind in $file." -ErrorAction Stop }

    # If needed, read the contents of specific file to $text and release the file so to use streamwriter later
        #Get the entry in the archive that you want to modify
        $zippedEntry = $fileZip.Entries | Where-Object { $_.FullName -eq $filePathToFind }
        if($zippedEntry -eq $null){Write-Error "Could not find entry in zip file" -ErrorAction Stop}
        #Open the file as a stream
        $desiredFile = [System.IO.StreamReader]($zippedEntry).Open() 
        #Read the entire contents to a string variable (Maybe you could manipulate the stream but not sure how to do that)
        $text = $desiredFile.ReadToEnd()

        #Cleanup
        $desiredFile.Close() | Out-Null
        $desiredFile.Dispose()| Out-Null

        #Modify the contents as needed. In this case I am just setting the contents to a bunch of numbers
        [string]$newText = ((1..1000) | % {"$_`n"})

        #Delete the entry in the archive
        $zippedEntry.Delete()
        #Create a new (empty) entry at the path inside the archive
        $newEntry = $fileZip.CreateEntry($filePathToFind)

        #Open the new entry as a stream and write the new text to it
        $stream = [System.IO.StreamWriter] $newEntry.Open()
        $stream.Write($newText)
        $stream.Close()
}
catch {
    throw
}
finally{
    # You want to dispose of everything in a finally block so that the objects get removed even if an error is thrown 
    $desiredFile.Close() | Out-Null
    $desiredFile.Dispose()| Out-Null
    $stream.Close() | Out-Null
    $fileZip.Dispose()| Out-Null
}
Write-Host "Zipped file update complete"
Write-Host ""

# Check zip size and individual file sizes after operation (Just to test. Will delete files on your computer!!!!)
Write-Host "test zip file size after replacement: $(Get-ChildItem $testZipPath | select -ExpandProperty Length)"
$FollowUpTestPath = "$(Split-Path $testZipPath -Parent)\FollowUpTest"
Remove-Item $FollowUpTestPath -Recurse -Force -ErrorAction SilentlyContinue
If(-not (Test-Path $FollowUpTestPath)){New-Item -Path $FollowUpTestPath -ItemType Directory | Out-Null}
[System.IO.Compression.ZipFile]::ExtractToDirectory($testZipPath, $FollowUpTestPath)
Write-Host "File sizes after operation: "
Get-ChildItem $FollowUpTestPath | foreach { Write-Host "filename: $($_.Name), length: $($_.Length)"}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM