转换现有函数以处理多个文件以解压缩

时间:2022-01-11 00:13:51

I have an existing working code to unzip the file in gz format:

我有一个现有的工作代码来解压缩gz格式的文件:

Function DeGZip-File{
    Param(
        $infile,
        $outfile = ($infile -replace '\.gz$','')
    )

    $input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
    $output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
    $gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress)

    $buffer = New-Object byte[](1024)
    while($true){
        $read = $gzipstream.Read($buffer, 0, 1024)
        if ($read -le 0){break}
        $output.Write($buffer, 0, $read)
    }
    $gzipStream.Close()
    $output.Close()
    $input.Close()
}
$infile="\\loction of the file\filename.gz"
DeGZip-File $infile

Is it possible to use this code to decompress all of the .gz files from the folder? And how would parameters look like to be passed to the script. I assume that now instead of the file name it should look for the input directory and destination folder.

是否可以使用此代码解压缩文件夹中的所有.gz文件?参数如何传递给脚本。我假设现在应该查找输入目录和目标文件夹而不是文件名。

2 个解决方案

#1


As it currently stands it only looks like you asking how to encorporate your function into a loop. Etan Reisner was trying to help you do just that. To build on his comment there are a couple of things you could do. This information is located in about_functions

目前它只是看起来像你问如何将你的功能融入循环。 Etan Reisner试图帮助你做到这一点。在他的评论的基础上,你可以做一些事情。此信息位于about_functions中

$path = "c:\temp\somepath"
Get-ChildItem -Path $path -Filter "*.gz" | ForEach-Object{
    DeGZip-File -inifile $_.FullName
    # Or the following would also work
    # DeGZip-File $_.FullName
}

-outfile could be considered optional based on how you have your function set up. If you need to declare that with the function call then you would just be doing this in the loop

根据您的功能设置方式,可以认为-outfile是可选的。如果你需要通过函数调用声明它,那么你只需要在循环中执行此操作

DeGZip-File -inifile $_.FullName -outfile "otherFileName"

or

DeGZip-File $_.FullName "SomehtingElse"

Aside

Consider looking into Advanced Functions and you can make your function accept pipeline input.

考虑查看高级功能,您可以使您的功能接受管道输入。

#2


As others have mentioned, you could simply incorporate your function into a ForEach-Object loop. Alternatively if you make two parameter sets, and in one leave it like you have it, and the other one accept pipeline values on your parameter, and make that parameter a [FileInfo] object, you could easily use Get-ChildObject to pipe to your function and not even have to use a loop. As for wanting your output in another folder, add a parameter to the function, and a little internal logic to accommodate that...

正如其他人所提到的,您可以简单地将您的函数合并到ForEach-Object循环中。或者,如果您创建两个参数集,并且在一个参数集中保留它,并且另一个参数集接受参数上的管道值,并将该参数设置为[FileInfo]对象,则可以轻松地使用Get-ChildObject来管道功能,甚至不必使用循环。至于想要在另一个文件夹中输出,请在函数中添加一个参数,并使用一点内部逻辑来适应...

Function DeGZip-File{
[cmdletbinding(DefaultParameterSetName='Piped')]
    Param(
        [Parameter(ParameterSetName='Direct')][String]$infile,
        [Parameter(ParameterSetName='Direct')][String]$outfile = ($infile -replace '\.gz$',''),
        [Parameter(ParameterSetName='Piped',ValueFromPipeline=$true)][System.IO.FileInfo[]]$PipedFile,
        [Parameter(ParameterSetName='Piped')]$Redirect=$null,
        [Switch]$PassThru
    )

Process{
    If($PsCmdlet.ParameterSetName -eq 'Piped'){
        $infile = $PipedFile.FullName
        $outfile = If([string]::IsNullOrEmpty($Redirect)){$infile -replace '\.gz$',''}else{Join-Path $Redirect -ChildPath ($PipedFile.BaseName)}
    }

    $inputfile = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
    $output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
    $gzipStream = New-Object System.IO.Compression.GzipStream $inputfile, ([IO.Compression.CompressionMode]::Decompress)

    $buffer = New-Object byte[](1024)

    $read = $gzipstream.Read($buffer, 0, 1024)
    Do{
        $output.Write($buffer, 0, $read)
        $read = $gzipstream.Read($buffer, 0, 1024)
    }While($read -gt 0)

    $gzipStream.Close()
    $output.Close()
    $inputfile.Close()

    If($PassThru){[System.IO.FileInfo]$outfile}
    }
}

I also added a -PassThru switch in case you want to see the files that it extracted.

我还添加了-PassThru开关,以防您想要查看它提取的文件。

Edit: I forgot to include a usage example, my bad...

编辑:我忘了包含一个用法示例,我的坏...

Get-ChildItem "C:\Temp\GZippedFiled\*.gz" | DeGZip-File -Redirect "C:\Temp\Unzipped" -PassThru

That will unzip all of the .GZ files in the "C:\Temp\GZippedFiled" folder, and will write the decompressed files with the same (minus .gz) file name in the "C:\Temp\Unzipped" folder. It will also show you the files that it extracts, displaying the [fileinfo] object for each (Mode, LastWriteTime, Length, and Name). Or you could do it more simply and just pipe to the function without any parameters, and it would extract them in place and not output anything to the console.

这将解压缩“C:\ Temp \ GZippedFiled”文件夹中的所有.GZ文件,并将在“C:\ Temp \ Unzipped”文件夹中写入具有相同(减去.gz)文件名的解压缩文件。它还会显示它提取的文件,显示每个文件的[fileinfo]对象(Mode,LastWriteTime,Length和Name)。或者你可以更简单地做到这一点,只需管道到没有任何参数的函数,它会在适当的位置提取它们而不向控制台输出任何内容。

It also accepts the old style of usage, ala:

它也接受旧的用法,ala:

DeGZip-File -infile "C:\Path\To\File.gz" -outfile "C:\Path\To\NewFile.ext"

Edit2: Ok, just to make sure I understand the issue in your comment. Let us say that you have 2 files compressed:

编辑2:好的,只是为了确保我在你的评论中理解这个问题。我们假设您压缩了2个文件:

C:\Temp\Resume.docx.gz
C:\Temp\Cover Letter.docx.gz

You want to unzip them, and store the resultant files in C:\Temp\Unzipped (the destination folder should already exist). Your script should have the function up top, then you can define paths if so desired, and then pipe Get-ChildItem to the function. It should look something like this:

您想要解压缩它们,并将结果文件存储在C:\ Temp \ Unzipped中(目标文件夹应该已经存在)。您的脚本应该具有顶部的功能,然后您可以根据需要定义路径,然后将Get-ChildItem传递给函数。它应该看起来像这样:

Function DeGZip-File{
    <function code goes here>
}

$FullPath = 'C:\Temp\'
$DestinationPath = 'C:\Temp\Unzipped'

Get-ChildItem -Path $fullpath -Filter "*.gz" | DeGZip-File -Redirect $destinationpath -PassThru

I literally just copied the function from this answer to a fresh PowerShell ISE instance, put 2 .gz files in my C:\Temp folder, created a C:\Temp\Unzipped folder, and ran that code above. It functioned perfectly. The files extracted, and it showed me the details of them as it did it. The trailing backslash on the path doesn't matter, either, both, or neither of the paths could have or not have the backslash at the end and it won't make a difference because of join-path sterilizing it.

我只是将这个答案中的函数复制到一个新的PowerShell ISE实例,将2 .gz文件放在我的C:\ Temp文件夹中,创建了一个C:\ Temp \ Unzipped文件夹,然后运行上面的代码。它功能完美。提取的文件,它向我展示了它们的详细信息。路径上的尾随反斜杠也无关紧要,或两条路径都没有或者没有反斜杠,并且由于连接路径消毒它不会产生差异。

#1


As it currently stands it only looks like you asking how to encorporate your function into a loop. Etan Reisner was trying to help you do just that. To build on his comment there are a couple of things you could do. This information is located in about_functions

目前它只是看起来像你问如何将你的功能融入循环。 Etan Reisner试图帮助你做到这一点。在他的评论的基础上,你可以做一些事情。此信息位于about_functions中

$path = "c:\temp\somepath"
Get-ChildItem -Path $path -Filter "*.gz" | ForEach-Object{
    DeGZip-File -inifile $_.FullName
    # Or the following would also work
    # DeGZip-File $_.FullName
}

-outfile could be considered optional based on how you have your function set up. If you need to declare that with the function call then you would just be doing this in the loop

根据您的功能设置方式,可以认为-outfile是可选的。如果你需要通过函数调用声明它,那么你只需要在循环中执行此操作

DeGZip-File -inifile $_.FullName -outfile "otherFileName"

or

DeGZip-File $_.FullName "SomehtingElse"

Aside

Consider looking into Advanced Functions and you can make your function accept pipeline input.

考虑查看高级功能,您可以使您的功能接受管道输入。

#2


As others have mentioned, you could simply incorporate your function into a ForEach-Object loop. Alternatively if you make two parameter sets, and in one leave it like you have it, and the other one accept pipeline values on your parameter, and make that parameter a [FileInfo] object, you could easily use Get-ChildObject to pipe to your function and not even have to use a loop. As for wanting your output in another folder, add a parameter to the function, and a little internal logic to accommodate that...

正如其他人所提到的,您可以简单地将您的函数合并到ForEach-Object循环中。或者,如果您创建两个参数集,并且在一个参数集中保留它,并且另一个参数集接受参数上的管道值,并将该参数设置为[FileInfo]对象,则可以轻松地使用Get-ChildObject来管道功能,甚至不必使用循环。至于想要在另一个文件夹中输出,请在函数中添加一个参数,并使用一点内部逻辑来适应...

Function DeGZip-File{
[cmdletbinding(DefaultParameterSetName='Piped')]
    Param(
        [Parameter(ParameterSetName='Direct')][String]$infile,
        [Parameter(ParameterSetName='Direct')][String]$outfile = ($infile -replace '\.gz$',''),
        [Parameter(ParameterSetName='Piped',ValueFromPipeline=$true)][System.IO.FileInfo[]]$PipedFile,
        [Parameter(ParameterSetName='Piped')]$Redirect=$null,
        [Switch]$PassThru
    )

Process{
    If($PsCmdlet.ParameterSetName -eq 'Piped'){
        $infile = $PipedFile.FullName
        $outfile = If([string]::IsNullOrEmpty($Redirect)){$infile -replace '\.gz$',''}else{Join-Path $Redirect -ChildPath ($PipedFile.BaseName)}
    }

    $inputfile = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
    $output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
    $gzipStream = New-Object System.IO.Compression.GzipStream $inputfile, ([IO.Compression.CompressionMode]::Decompress)

    $buffer = New-Object byte[](1024)

    $read = $gzipstream.Read($buffer, 0, 1024)
    Do{
        $output.Write($buffer, 0, $read)
        $read = $gzipstream.Read($buffer, 0, 1024)
    }While($read -gt 0)

    $gzipStream.Close()
    $output.Close()
    $inputfile.Close()

    If($PassThru){[System.IO.FileInfo]$outfile}
    }
}

I also added a -PassThru switch in case you want to see the files that it extracted.

我还添加了-PassThru开关,以防您想要查看它提取的文件。

Edit: I forgot to include a usage example, my bad...

编辑:我忘了包含一个用法示例,我的坏...

Get-ChildItem "C:\Temp\GZippedFiled\*.gz" | DeGZip-File -Redirect "C:\Temp\Unzipped" -PassThru

That will unzip all of the .GZ files in the "C:\Temp\GZippedFiled" folder, and will write the decompressed files with the same (minus .gz) file name in the "C:\Temp\Unzipped" folder. It will also show you the files that it extracts, displaying the [fileinfo] object for each (Mode, LastWriteTime, Length, and Name). Or you could do it more simply and just pipe to the function without any parameters, and it would extract them in place and not output anything to the console.

这将解压缩“C:\ Temp \ GZippedFiled”文件夹中的所有.GZ文件,并将在“C:\ Temp \ Unzipped”文件夹中写入具有相同(减去.gz)文件名的解压缩文件。它还会显示它提取的文件,显示每个文件的[fileinfo]对象(Mode,LastWriteTime,Length和Name)。或者你可以更简单地做到这一点,只需管道到没有任何参数的函数,它会在适当的位置提取它们而不向控制台输出任何内容。

It also accepts the old style of usage, ala:

它也接受旧的用法,ala:

DeGZip-File -infile "C:\Path\To\File.gz" -outfile "C:\Path\To\NewFile.ext"

Edit2: Ok, just to make sure I understand the issue in your comment. Let us say that you have 2 files compressed:

编辑2:好的,只是为了确保我在你的评论中理解这个问题。我们假设您压缩了2个文件:

C:\Temp\Resume.docx.gz
C:\Temp\Cover Letter.docx.gz

You want to unzip them, and store the resultant files in C:\Temp\Unzipped (the destination folder should already exist). Your script should have the function up top, then you can define paths if so desired, and then pipe Get-ChildItem to the function. It should look something like this:

您想要解压缩它们,并将结果文件存储在C:\ Temp \ Unzipped中(目标文件夹应该已经存在)。您的脚本应该具有顶部的功能,然后您可以根据需要定义路径,然后将Get-ChildItem传递给函数。它应该看起来像这样:

Function DeGZip-File{
    <function code goes here>
}

$FullPath = 'C:\Temp\'
$DestinationPath = 'C:\Temp\Unzipped'

Get-ChildItem -Path $fullpath -Filter "*.gz" | DeGZip-File -Redirect $destinationpath -PassThru

I literally just copied the function from this answer to a fresh PowerShell ISE instance, put 2 .gz files in my C:\Temp folder, created a C:\Temp\Unzipped folder, and ran that code above. It functioned perfectly. The files extracted, and it showed me the details of them as it did it. The trailing backslash on the path doesn't matter, either, both, or neither of the paths could have or not have the backslash at the end and it won't make a difference because of join-path sterilizing it.

我只是将这个答案中的函数复制到一个新的PowerShell ISE实例,将2 .gz文件放在我的C:\ Temp文件夹中,创建了一个C:\ Temp \ Unzipped文件夹,然后运行上面的代码。它功能完美。提取的文件,它向我展示了它们的详细信息。路径上的尾随反斜杠也无关紧要,或两条路径都没有或者没有反斜杠,并且由于连接路径消毒它不会产生差异。