使用PowerShell时,将数据保存到文件是一个非常常见的任务。可能比你意识到的更多选择。让我们从基础知识开始,并进入更高级的选项。

指数

使用文件路径

我们将通过向您展示使用文件路径的命令来启动此操作。

测试路径

测试路径 当您开始使用文件时,是众所周知的命令之一。在尝试使用它之前,它允许您测试文件夹或文件。

If( Test-Path -Path $Path )
{
    Do-Stuff -Path $Path
}

分裂路径

分裂路径 将占用文件的完整路径并为您提供父文件夹路径。

PS:> Split-Path -Path 'c:\users\kevin.marquette\documents'
c:\users\kevin.marquette

If you need the file or folder at the end of the path, you can use the -Leaf argument to get it.

PS:> Split-Path -Path 'c:\users\kevin.marquette\documents' -Leaf
documents

加入路径

加入路径 可以将文件夹和文件路径加入。

PS:> Join-Path -Path $env:temp -ChildPath testing
C:\Users\kevin.marquete\AppData\Local\Temp\testing

我随时使用这个我加入存储在变量中的位置。您不必担心如何处理反斜杠,因为为您提供它。如果您的变量均在它们中倒置反向架,则它也会排出它。

决心路径

决心路径 会给你一个地方的完整路径。重要的是,它将为您扩展通配符。如果有多个匹配项,您将获得一系列值。

决心路径 -Path 'c:\users\*\documents'

Path
----
C:\users\kevin.marquette\Documents
C:\users\Public\Documents

这将枚举所有本地用户文档文件夹。

我通常在任何路径值上使用它,即我将用户输入到接受多个文件的函数中。我发现它是将通配符支持添加到参数的简单方法。

保存和阅读数据

既然我们将所有这些辅助cmdlet脱离了,我们可以谈谈我们为保存和读取数据的选项。

I use the $Path and $Data variables to represent your file path and your data in these examples. I do this to keep the samples cleaner and it better reflects how you would use them in a script.

带外档的基本重定向

电源外壳 was introduced with Out-File as the way to save data to files. Here is what the help on that looks like.

Get-Help Out-File
<#
SYNOPSIS
    Sends output to a file.
DESCRIPTION
    The Out-File cmdlet sends output to a file. You can use this cmdlet instead of the redirection operator (>) when you need to use its parameters.
#>

For anyone coming from batch file, Out-File is the basic replacement for the redirection operator >. Here is a sample of how to use it.

'This is some text' | Out-File -FilePath $Path

这是一个基本命令,我们很长一段时间。这是一个显示一些限制的第二个例子。

 Get-ChildItem |
     Select-Object Name, Length, LastWriteTime, Fullname |
     Out-File -FilePath $Path

从我的临时文件夹执行时,生成的文件看起来像这样:

Name
Length  LastWriteTime          FullName
----
------  -------------          --------
3A1BFD5A-88A6-487E-A790-93C661B9B904                 9/6/2016 10:38:54 AM   C:\Users\kevin.marqu...
acrord32_sbx                                         9/4/2016 10:18:18 AM   C:\Users\kevin.marqu...
TCD789A.tmp                                          9/8/2016 12:27:29 AM   C:\Users\kevin.marqu...

You can see that the last column of values are cut short. Out-File is processing objects for the console but redirects the output to a file. All the issues you have getting something to format in the console will show up in your output file. The good news is that we have lots of other options for this that I will cover below.

使用add-content保存文本数据

I personally don’t use Out-File and prefer to use the Add-Content and Set-Content commands. There is also a Get-Content command that goes with them to read file data.

$data | Add-Content -Path $Path
Get-Content -Path $Path

Add-Content will create and append to files. Set-Content will create and overwrite files.

只要性能在脚本中没有一个关键因素,这些都是良好的通用命令。它们非常适合个人或小内容请求。对于大整套数据,在性能超过可读性的情况下,我们可以转向.NET Framework。我会回到这个。

使用get-content -raw导入数据

Get-Content 是读取数据的goto命令。默认情况下,此命令将读取文件的每一行。你最终有一系列字符串。这也很好地通过管道。

The -Raw parameter will bring the entire contents in as a multi-line string. This also performs faster because fewer objects are getting created.

Get-Content -Path $Path -Raw

使用Export-CSV保存基于列的数据

If you ever need to save data for Excel, Export-CSV is your starting point. This is good for storing an object or basic structured data that can be imported later. The CSV format is comma separated values in a text file. Excel is often the default viewer for CSV files.

If you want to import Excel data in PowerShell, save it as a CSV and then you can use Import-CSV. There are other ways to do it but this is by far the easiest.

$data | Export-CSV -Path $Path
Import-CSV -Path $Path

-NotyPeinFormation.

Export-CSV will insert type information into the first line of the CSV. If you don’t want that, then you can specify the -NotyPeinFormation. parameter.

$data | Export-CSV -Path $Path -NoTypeInformation

使用Export-Clixml保存丰富的对象数据

The Export-CliXml command is used to save full objects to a file and then import them again with Import-CliXml. This is for objects with nested values or complex datatypes. The raw data will be a verbose serialized object in XML. The nice thing is that you can save a an object to the file and when you import it, you will get that object back.

Get-Date | Export-Clixml date.clicml
$date = Import-Clixml .\date.clicml
$date.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DateTime                                 System.ValueType

This serialized format is not intened for be viewd or edited directly. Here is what the date.clixml file looks like:

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
    <Obj RefId="0">
        <DT>2017-03-17T00:00:00.3522798-07:00</DT>
        <MS>
            <Obj N="DisplayHint" RefId="1">
                <TN RefId="0">
                    <T>Microsoft.PowerShell.Commands.DisplayHintType</T>
                    <T>System.Enum</T>
                    <T>System.ValueType</T>
                    <T>System.Object</T>
                </TN>
                <ToString>DateTime</ToString>
                <I32>2</I32>
            </Obj>
        </MS>
    </Obj>
</Objs>

不要担心试图了解它。你不打算挖掘它。

这是另一个命令,即我不经常找到自己。如果我有一个嵌套或分层数据集,那么JSON是我的GOTO方式来保存该信息。

使用ConvertTo-Json保存结构化数据

When my data is nested and I may want to edit it by hand, then I use ConvertTo-Json to convert it to JSON. ConvertFrom-Json will convert it back into an object. These commands do not save or read from files on their own. You will have to turn to Get-Content and Set-Content for that.

$Data = @{
    Address = @{
        Street = '123 Elm'
        State  = 'California'
    }
}

$Data | ConvertTo-Json | Add-Content  -Path $Path
$NewData = Get-Content -Path $Path -Raw | ConvertFrom-Json
$NewData.Address.State

There is one important thing to note on this example. I used a [hashtable] for my $Data but ConvertFrom-Json returns a [PSCustomObject] instead. This may not be a problem but there is not an easy fix for it.

Also note the use of the Get-Content -Raw in this example. ConvertFrom-Json expects one string per object.

以下是json文件从上面的内容:

{
    "Address":  {
        "State":  "California",
        "Street":  "123 Elm"
    }
}

您会注意到,这与原始哈希特相似。这就是为什么Json是一种流行的格式。如果需要,很容易读取,理解和编辑。我在我自己的项目中一直在使用这个配置文件。

其他选择和细节

所有这些cmdlet都很易于使用。我们还有一些其他参数和访问.NET获取更多选项。

Get-Content -ReadCount

The -ReadCount parameter on Get-Content defines how many lines that Get-Content will read at once. There are some situations where this can improve the memory overhead of working with larger files.

这通常包括将结果输出到可以在进入时处理它们的东西,并且不需要保留输入数据。

$dataset = @{}
Get-Content -Path $path -ReadCount 15 |
    Where-Object {$PSItem -match 'error'} |
    ForEach-Object {$dataset[$PSItem] += 1}

This example will count how many times each error shows up in the $Path. This pipeline can process each line as it is read from the file.

您可能没有代码频繁地利用,但这是要注意的一个很好的选择。

使用system.io.file更快地阅读

CMDLETS提供的易用性可以以较小的原始性能成本。足够小,你不会注意到你所做的大部分脚本。当那一天来到你需要更多的速度时,你会发现自己转到本地.NET命令。谢天谢地,他们很容易与之合作。

[System.IO.File]::ReadAllLines( ( Resolve-Path $Path ) )

This is just like Get-Content -Path $Path in that you will end up with a collection full of strings. You can also read the data as a multi-line string.

[System.IO.File]::ReadAllText( ( Resolve-Path $Path ) )

The $Path must be the full path or it will try to save the file to your C:\Windows\System32 folder. This is why I use 决心路径 in this example.

以下是我围绕这些.NET调用构建的示例cmdlet: 进口内容

使用system.io.streamWriter写入

On that same note, we can also use System.IO.StreamWriter to save data. It is not always faster than the native Cmdlets. This one clearly falls into the rule that if performance matters, test it.

System.IO.StreamWriter 也比本机cmdlet更复杂。

try
{
    $stream = [System.IO.StreamWriter]::new( $Path )
    $data | ForEach-Object{ $stream.WriteLine( $_ ) }
}
finally
{
    $stream.close()
}

We have to open a StreamWriter to a $path. Then we walk the data and save each line to the StreamWriter. Once we are done, we close the file. This one also requires a full path.

I had to add error handling around this one to make sure the file was closed when we were done. You may want to add a catch in there for custom error handling.

This should work very well for string data. If you have issues, you may want to call the .ToString() method on the object you are writing to the stream. If you need more flexibility, just know that you have the whole .Net framework available at this point.

保存XML

If you are working with XML files, you can call the Save() method on the XML object.

$Xml = [xml]"<r><data/></r>"
$Path = (join-path $pwd 'File.xml')
$Xml.Save($Path)

Just like the other .Net methods in System.IO, you need to specify the full path to the file. I use $pwd in this example because it is an automatic variable that contains the result of Get-Location (local path).

关于编码的快速注意事项

文件编码是在保存到磁盘时将数据转换为二进制文件的方式。大部分时间它只是有效,除非你做了很多跨平台工作。

If you are running into issues with encoding, most of the CmdLets support specifying the encoding. If you want to default the encoding for each command, you can use the $psdefaultparametervalual. hashtable like this:

# Create default values for any parameter
# $psdefaultparametervalual.["Function:Parameter"]  = $value

# Set the default file encoding
$psdefaultparametervalual.["Out-File:Encoding"]    = "UTF8"
$psdefaultparametervalual.["Set-Content:Encoding"] = "UTF8"
$psdefaultparametervalual.["Add-Content:Encoding"] = "UTF8"
$psdefaultparametervalual.["Export-CSV:Encoding"]  = "UTF8"

您可以找到更多有关如何使用的信息 psdefaultparametervalual. 在我的帖子中 Hashtables..

包起来

使用文件是如此常用任务,您应该花时间了解这些选项。希望你看到一些新的东西,可以把它放在自己的脚本中。

以下是实现我们讨论的想法的两个功能