首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >能否暂时扩展内存中的.ZIP文件(7-Zip),操作内容并使用PowerShell丢弃它?

能否暂时扩展内存中的.ZIP文件(7-Zip),操作内容并使用PowerShell丢弃它?
EN

Stack Overflow用户
提问于 2022-11-05 22:57:28
回答 1查看 111关注 0票数 0

是否可以暂时将.ZIP文件(7-Zip)的内容扩展到内存中的变量,操作内容并使用PowerShell丢弃它?

我目前正在扩展档案,它提取了一个"log.dat“文件。然后我读取了这个日志文件的内容,做了分析并删除了"log.dat“文件。但我得做500,000次,这可能会对驾驶有害。所以现在,我的解决办法是创建一个R:\ RamDrive并像这样使用它

代码语言:javascript
复制
$zipFiles = Get-ChildItem -Filter '*.zip' -r
foreach($zip in $zipFiles) {

    Expand-7Zip -ArchiveFileName $zip.FullName -TargetPath 'R:\'

    Select-String -Path 'R:\log.dat' -Pattern "dataToSearchFor"  | ForEach-Object {
        # do analysis
    }

    Remove-Item 'R:\log.dat'

}

我需要的是

代码语言:javascript
复制
$zipFiles = Get-ChildItem -Filter '*.zip' -r
foreach($zip in $zipFiles) {

    $extractedFiles = Expand-7Zip -ArchiveFileName $zip.FullName

    $logFile = $extractedFiles[0] # log.dat file is unique in file
    Select-String $logFile -Pattern "dataToSearchFor"  | ForEach-Object {
        # do analysis
    }
}

顺便说一句:我必须为PowerShell使用7-zip库,因为档案中使用了压缩方法。

代码语言:javascript
复制
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Set-PSRepository -Name 'PSGallery' -SourceLocation "https://www.powershellgallery.com/api/v2" -InstallationPolicy Trusted
Install-Module -Name 7Zip4PowerShell -Force
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-06 02:49:36

他们说“第三次是一种魅力。”

这是我第三次尝试解决这个问题。第二次尝试的信息仍然有效,但是只对某些压缩文件有效,所以您可以在这个答案中找到更深入的信息。

First,从https://www.7-zip.org/安装7-zip的最新版本.

在我的例子中,安装了7z2201-x64.exe。

第二个,下载SevenZipSharp的Nuget包,然后使用7-Zip打开包,导航到sevenzipsharp.net45.1.0.19.nupkg\lib\net45\并将SevenZipSharp.dll保存到与PowerShell脚本相同的位置。

以下任何一项似乎都适用于下载:https://www.nuget.org/api/v2/package/SevenZipSharp.Net45/1.0.19

https://globalcdn.nuget.org/packages/sevenzipsharp.net45.1.0.19.nupkg

第三版,注意安装7-Zip的7z.dll文件的位置.在我的例子中,是C:\Program Files\7-Zip\7z.dll

Forth,将以下行添加到PowerShell脚本的顶部,确保给SetLibraryPath的路径设置为7-Zip在上面的第三步中找到的7z.dll的路径。

代码语言:javascript
复制
using namespace System.IO
Add-Type -Path "$PSScriptRoot\SevenZipSharp.dll"

[SevenZip.SevenZipExtractor]::SetLibraryPath('C:\Program Files\7-Zip\7z.dll')

第五,添加您想要运行的代码。

此示例读取在存档文件SevenZipTest.zip中找到的所有文件路径名称,这些文件路径与PowerShell脚本的路径相同:

代码语言:javascript
复制
function ReadFilenamesIn7Zip {
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Path
    )
    [SevenZip.SevenZipExtractor]$ZipArchive = [SevenZip.SevenZipExtractor]::new($Path)
    foreach($ArchiveFileInfo in $ZipArchive.ArchiveFileData) {
        $ArchiveFileInfo.FileName
    }
    $ZipArchive.Dispose()
}

ReadFilenamesIn7Zip "$PSScriptRoot\SevenZipTest.zip"

此示例从名为Test.TXT的第一个内部文件中读取所有文件行,该文件位于与PowerShell脚本相同的路径中的归档文件SevenZipTest.zip中:

代码语言:javascript
复制
function ReadFileIn7Zip {
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Path,
        [Parameter(Mandatory = $true, Position = 1)]
        [string]$FileToUnzip,
        [Parameter(Mandatory = $false, Position = 2)]
        [int]$FileIndex = -1
    )
    [SevenZip.SevenZipExtractor]$ZipArchive = [SevenZip.SevenZipExtractor]::new($Path)
    $ThisFileIndex = 0
    foreach($ArchiveFileInfo in $ZipArchive.ArchiveFileData) {
        $FileNameNoPath = Split-Path $ArchiveFileInfo.FileName -leaf
        if($FileNameNoPath -eq $FileToUnzip) {
            if($FileIndex -lt 0 -or $FileIndex -eq $ThisFileIndex) {
                $MemoryStream = [System.IO.MemoryStream]::new()
                $ZipArchive.ExtractFile($ArchiveFileInfo.Index, $MemoryStream)
                [StreamReader]$ZipReader = [StreamReader]::new($MemoryStream)
                $MemoryStream.Position = 0
                while ($null -ne ($line = $ZipReader.ReadLine())) {
                    $line
                }
                $ZipReader.Dispose()
                # $MemoryStream.Dispose() # Not needed: https://learn.microsoft.com/en-us/dotnet/api/system.io.memorystream?view=net-6.0#remarks
            }
            $ThisFileIndex++
        }
    }
    $ZipArchive.Dispose()
}

ReadFileIn7Zip "$PSScriptRoot\SevenZipTest.zip" "Test.TXT" 0

ReadFilenamesIn7Zip和ReadFileIn7Zip的功能本质上与下面的ReadFilenamesInZip和ReadFileInZip示例相同。例如,如果您查看下面ReadFileInZip函数的功能,当不使用-FileIndex参数调用它时,它将返回与-FileToUnzip参数匹配的所有文件的所有文本,这对于ReadFileIn7Zip也是如此。

注:{来自第二次尝试的信息低于此点。}

下面的* Deflate**,信息只对压缩有 ** BZip2**,和** LZMA压缩的压缩文件有效

本例以zip文件01_SQLite.zip为例,搜索任何名为App.config的文件。这非常类似于注释中提供的链接PowerShell jdweng的读取版本和,但是有几处修改,比如将文件存储在StringBuilder中。

更新:代码在VSCode中工作,但发现它不在PowerShell 5.1终端中工作。两者应该是相同的,但由于某些原因,它们不是-而且VSCode被设置为在每次运行脚本之前重新加载PowerShell,所以不应该有任何预加载的程序集。

解决方案:谢谢圣地亚哥,在代码中添加了Add-Type -Assembly System.IO.Compression, System.IO.Compression.FileSystem。通过关闭PowerShell终端、重新打开它并运行脚本来验证它的有效性:

代码语言:javascript
复制
using namespace System.IO
using namespace System.IO.Compression
using namespace System.IO.MemoryStream
using namespace System.Text
Add-Type -Assembly System.IO.Compression, System.IO.Compression.FileSystem

$ZipFilePath = "$PSScriptRoot\01_SQLite.zip"

[ZipArchive]$ZipArchive = [ZipFile]::Open($ZipFilePath, [ZipArchiveMode]::Read)

[StringBuilder]$SB = [StringBuilder]::new()
foreach($ZipEntry in $ZipArchive.Entries) {
    if($ZipEntry.Name -eq "App.config") {
        [StreamReader]$ZipReader = [StreamReader]::new($ZipEntry.Open())
        while ($null -ne ($line = $ZipReader.ReadLine())) {
            $null = $SB.AppendLine($line)
        }
        # Do something with the file stored in StringBuilder $SB
        Write-Host "Found file $($ZipEntry.FullName)"
        Write-Host $SB.ToString()
        Write-Host
        $null = $SB.Clear()
        $ZipReader.Dispose()
    }
}
$ZipArchive.Dispose()

更多用途和更有用的代码:

此函数返回Zip文件中找到的文件路径和名称:

代码语言:javascript
复制
using namespace System.IO
using namespace System.IO.Compression
Add-Type -Assembly System.IO.Compression, System.IO.Compression.FileSystem

function ReadFilenamesInZip {
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Path
    )
    [ZipArchive]$ZipArchive = [ZipFile]::Open($Path, [ZipArchiveMode]::Read)
    foreach($ZipEntry in $ZipArchive.Entries) {
        $ZipEntry.FullName
    }
    $ZipArchive.Dispose()
}

例如,从01_SQLite.zip文件中读取文件路径名:

代码语言:javascript
复制
$ZipFilePath = "$PSScriptRoot\01_SQLite.zip"
$FileNames = ReadFilenamesInZip -Path $ZipFilePath
$FileNames

因此产生了这一产出:

代码语言:javascript
复制
screenshot.png
sqlite_test.sln
sqlite_test/App.config
sqlite_test/App.xaml
sqlite_test/App.xaml.cs
sqlite_test/MainWindow.xaml
sqlite_test/MainWindow.xaml.cs
sqlite_test/packages.config
sqlite_test/Properties/AssemblyInfo.cs
sqlite_test/Properties/Resources.Designer.cs
sqlite_test/Properties/Resources.resx
sqlite_test/Properties/Settings.Designer.cs
sqlite_test/Properties/Settings.settings
sqlite_test/sqlite_test.csproj

示例使用,从我创建的名为TestZip.zip的zip文件中读取文件路径名

代码语言:javascript
复制
$ZipFilePath = "$PSScriptRoot\TestZip.zip"
$FileNames = ReadFilenamesInZip -Path $ZipFilePath
$FileNames

因此产生了这一产出:

代码语言:javascript
复制
Folder1/Test.TXT
Folder2/Test.TXT
Test.TXT

此函数返回与某个文件名匹配的所有文件的内容:

代码语言:javascript
复制
using namespace System.IO
using namespace System.IO.Compression
Add-Type -Assembly System.IO.Compression, System.IO.Compression.FileSystem

function ReadFileInZip {
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Path,
        [Parameter(Mandatory = $true, Position = 1)]
        [string]$FileToUnzip,
        [Parameter(Mandatory = $false, Position = 2)]
        [int]$FileIndex = -1
    )
    [ZipArchive]$ZipArchive = [ZipFile]::Open($Path, [ZipArchiveMode]::Read)
    $ThisFileIndex = 0
    foreach($ZipEntry in $ZipArchive.Entries) {
        if($ZipEntry.Name -eq $FileToUnzip) {
            if($FileIndex -lt 0 -or $FileIndex -eq $ThisFileIndex) {
                [StreamReader]$ZipReader = [StreamReader]::new($ZipEntry.Open())
                while ($null -ne ($line = $ZipReader.ReadLine())) {
                    $line
                }
                $ZipReader.Dispose()
            }
            $ThisFileIndex++
        }
    }
    $ZipArchive.Dispose()
}

TestZip.zip中提取与文件名Test.TXT匹配的所有内部文件的内容的示例

代码语言:javascript
复制
$ZipFilePath = "$PSScriptRoot\TestZip.zip"
$FileLines = ReadFileInZip -Path $ZipFilePath -FileToUnzip 'Test.TXT'
if ($null -ne $FileLines) {
    Write-Host 'Found File(s):'
    $FileLines
} else {
    Write-Host 'File NOT found.'
}

因此产生了这一产出:

代码语言:javascript
复制
Found File(s):
### Folder 1 Text File ###
Random info in Folder 1 text file
### Folder 2 Text File ###
Random info in Folder 2 text file
### Root Text File ###
Random info in root text file

示例仅读取具有匹配名称的第一个文件的内容-

注意添加的-FileIndex 0

代码语言:javascript
复制
$ZipFilePath = "$PSScriptRoot\TestZip.zip"
$FileLines = ReadFileInZip -Path $ZipFilePath -FileToUnzip 'Test.TXT' -FileIndex 0
if ($null -ne $FileLines) {
    Write-Host 'Found File(s):'
    $FileLines
} else {
    Write-Host 'File NOT found.'
}

因此产生了这一产出:

代码语言:javascript
复制
Found File(s):
### Folder 1 Text File ###
Random info in Folder 1 text file

-FileIndex 0更改为-FileIndex 2可以得到以下结果:

代码语言:javascript
复制
Found File(s):
### Root Text File ###
Random info in root text file

将FileIndex更改为不指向zip中的文件的值(如-FileIndex 3 ),将得到以下结果:

代码语言:javascript
复制
File NOT found.
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74332064

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档