使用 Export-CSV 将“SEP=,”添加到 CSV 的开头

Joh*_*van 5 csv powershell byte-order-mark utf-8 export-to-csv

有没有一种干净的方法可以附加SEP=,到由 创建的 CSV 文件的开头Export-CSV

\n\n

注意:这是一个 XY 问题;有关我的根本问题的信息,请参阅下面为什么需要这个。我要求提供 SEP 部分,因为这似乎是最好的解决方案,因为我需要继续使用 UTF8 CSV,并且不希望用户必须更改其工作方式以避免出现问题。

\n\n

创建后修改文件

\n\n

简单的选择是这样的;然而感觉很混乱(即我们释放文件上的锁然后必须返回并更新它)。

\n\n
function Repair-Csv {\n    [CmdletBinding()]\n    Param (\n        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]\n        [string]$Path\n    )\n    Begin {\n        $sep = "SEP=,`r`n" \n    }\n    Process {\n        $sep + (Get-Content -Path $Path -Raw) | Set-Content -Path $Path\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

代理功能解决方案尝试

\n\n

我尝试创建一个代理函数(下面的代码),但发现包装的Export-CSV命令不会将其输出附加到我的调整文件中,而是读取我已经编写的内容并尝试用作SEP=列标题;所以我最终没有数据(除非我导出的对象的属性之一恰好被称为SEP=.

\n\n
# $MetaData = New-Object System.Management.Automation.CommandMetaData (Get-Command \'Export-CSV\')\n# [System.Management.Automation.ProxyCommand]::Create($MetaData)\nfunction Export-CsvAdvanced {\n    [CmdletBinding(DefaultParameterSetName=\'Delimiter\', SupportsShouldProcess=$true, ConfirmImpact=\'Medium\', HelpUri=\'http://go.microsoft.com/fwlink/?LinkID=113299\')]\n    param (\n        [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]\n        [psobject]\n        ${InputObject}\n        ,\n        [Parameter(Position=0)]\n        [ValidateNotNullOrEmpty()]\n        [string]\n        ${Path}\n        ,\n        [Alias(\'PSPath\')]\n        [ValidateNotNullOrEmpty()]\n        [string]\n        ${LiteralPath}\n        ,\n        [switch]\n        ${Force}\n        ,\n        [Alias(\'NoOverwrite\')]\n        [switch]\n        ${NoClobber}\n        ,\n        [ValidateSet(\'Unicode\',\'UTF7\',\'UTF8\',\'ASCII\',\'UTF32\',\'BigEndianUnicode\',\'Default\',\'OEM\')]\n        [string]\n        ${Encoding}\n        ,\n        [switch]\n        ${Append}\n        ,\n        [Parameter(ParameterSetName=\'Delimiter\', Position=1)]\n        [ValidateNotNull()]\n        [char]\n        ${Delimiter}\n        ,\n        [Parameter(ParameterSetName=\'UseCulture\')]\n        [switch]\n        ${UseCulture}\n        ,\n        [Alias(\'NTI\')]\n        [switch]\n        ${NoTypeInformation}\n        ,\n        [Alias(\'SEP\')]\n        [switch]\n        ${PrefixWithSep}\n    )\n    begin {\n        try {\n            $outBuffer = $null\n            if ($PSBoundParameters.TryGetValue(\'OutBuffer\', [ref]$outBuffer))\n            {\n                $PSBoundParameters[\'OutBuffer\'] = 1\n            }\n            if ($PrefixWithSep.IsPresent) {\n                if (!$Delimiter) {\n                    if ($UseCulture.IsPresent) {\n                        $Delimiter = [System.Globalization.CultureInfo]::CurrentCulture.TextInfo.ListSeparator\n                    } else {\n                        $Delimiter = \',\'\n                    }\n                }\n                $splat = @{}\n                if ($Encoding) { $splat.Add(\'Encoding\', $Encoding) }\n                if ($Force) { $splat.Add(\'Force\', $Force) }\n                if ($Append) { $splat.Add(\'Append\', $Append) }\n                if ($NoClobber) { $splat.Add(\'NoClobber\', $NoClobber) }\n                if ($PSCmdlet.ParameterSetName -eq \'PSPath\') {\n                    $splat.Add(\'LiteralPath\', $LiteralPath)\n                } else {\n                    $splat.Add(\'FilePath\', $Path)\n                }\n                ("SEP={0}`r`n" -f $Delimiter) | Out-File @splat\n                $PSBoundParameters.Remove(\'PrefixWithSep\') #Export-CSV won\'t understand our custom parameter, so remove it (NB: if this is not the first call this will already have been removed)\n                $PSBoundParameters[\'Append\'] = $true #we don\'t want to delete the file after adding a header\n                $PSBoundParameters[\'Force\'] = $true #Don\'t treat `SEP=,` as a heading when appending to the file\n            }\n\n            $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand(\'Microsoft.PowerShell.Utility\\Export-Csv\', [System.Management.Automation.CommandTypes]::Cmdlet)\n            $scriptCmd = {& $wrappedCmd @PSBoundParameters }\n            $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)\n            $steppablePipeline.Begin($PSCmdlet)\n        } catch {\n            throw\n        }\n    }\n    process {\n        try {\n            $steppablePipeline.Process($_)\n        } catch {\n            throw\n        }\n    }\n    end {\n        try {\n            $steppablePipeline.End()\n        } catch {\n            throw\n        }\n    }\n    <#\n    .ForwardHelpTargetName Microsoft.PowerShell.Utility\\Export-Csv\n    .ForwardHelpCategory Cmdlet\n    #>\n}\n\n#test populated\nGet-Process | Export-CsvAdvanced -Path \'c:\\temp\\processSep.csv\' -NoTypeInformation -PrefixWithSep\nGet-Process | Export-CsvAdvanced -Path \'c:\\temp\\process.csv\' -NoTypeInformation\n#test blank\n$blankArray = @()\n$blankArray | Export-CsvAdvanced -Path \'c:\\temp\\emptySep.csv\' -NoTypeInformation -PrefixWithSep\n$blankArray | Export-CsvAdvanced -Path \'c:\\temp\\empty.csv\' -NoTypeInformation\n
Run Code Online (Sandbox Code Playgroud)\n\n

我总是可以创建一个代理函数来ConvertTo-CSV添加流以将结果输出到文件;但这并不舒服(即,如果存在异常,尝试正确处理流会变得很复杂)。

\n\n

为什么需要这个?

\n\n

我并不严格需要 SEP 前缀;会有用的;但事实是我正在尝试解决另一个问题(所以这是一个XY 问题)。

\n\n

我有一些将数据输出到 CSV 的函数。\n在某些情况下,导出的文件是空白的(即没有结果)。在这种情况下,我仍然希望创建一个文件(即,很明显代码已运行但没有结果,而代码根本没有运行)。\n但是,我的 CSV 是 UTF8,当空白时显示为Excel 中的 BOM(即单元格 A1 包含\xc3\xaf\xc2\xbb\xc2\xbf)。

\n\n

由于我必须继续使用 CSV,并且理想情况下希望继续使用 UTF8,因此最好的解决方案似乎是添加一些内容;一项建议是为SEP=,指令添加前缀(这在与其他国家/地区的用户共享 CSV 时也很有用,因为这些国家/地区使用不同的默认分隔符)。

\n