【问题标题】:Import-Csv powershell with duplicate column headers具有重复列标题的 Import-Csv powershell
【发布时间】:2017-06-10 20:01:24
【问题描述】:

我需要在 PowerShell 中处理具有重复列标题的 csv 文件。他们有重复列的原因超出了我的范围。这就是生活。

我想使用 Import-Csv 以便我可以轻松处理数据,但由于存在重复列,我收到此错误:

Import-Csv : The member "PROC STAT" is already present.
At C:\Users\MyName\Documents\SomeFolder\testScript1.ps1:10 char:9
+ $csv2 = Import-Csv $files[0].FullName
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Import-Csv], ExtendedTypeSystemException
    + FullyQualifiedErrorId : AlreadyPresentPSMemberInfoInternalCollectionAdd,Microsoft.PowerShell.Commands.ImportCsvCommand

我可以通过进入每个 csv 文件并删除重复的列来手动解决问题。但这不是一个选择。它们有数百个,并且脚本需要定期运行。理想情况下,我正在寻找一种方法来以编程方式删除该列(Import-Csv 不起作用)或以编程方式更改列的名称(这样我就可以导入-Csv 并删除它)。有什么建议吗?

我的代码循环遍历所有文件:

$files = Get-ChildItem "C:\Users\MyName\Documents\SomeFolder\Data" -Filter *.csv

foreach($file in $files) {
    $csv = Import-Csv $file.FullName
}

【问题讨论】:

  • 提前知道表头顺序吗?
  • @MathiasR.Jessen 是的
  • 我可以使用Get-Content $file.FullName -First 1 从文件中获取第一行(标题)。但我不确定如何修改/写入新文件。

标签: powershell csv


【解决方案1】:

您可以使用Header 参数指定自定义标题名称:

Import-Csv .\file.csv -Header header1,header2,header3

这会将原始标题行视为普通行,因此跳过带有Select-Object的第一个输出对象:

Import-Csv .\file.csv -Header header1,header2,header3 |Select-Object -Skip 1

【讨论】:

    【解决方案2】:

    我也遇到过几次,并写了这个作为解决方法。即使所有/多个列名相同,它也适用于任何 csv。

    
        function Import-DuplicateHeaderCSV{
        <#
        # Synopsis
        Workaround function for the powershell error: "Import-Csv : The member "column_name" is already present." 
        This error is returned when attempting to use the Import-CSV cmdlet on a csv which has duplicate column names.
        
        # Description
        The headers are looped through, read in, and parsed into an array. 
        Duplicate headers are stored into a hash table e.g.{@columnName = numOccurences}.
        Multiple occurences of the header are supported by incrementing the value in the hashtable for each occurence. 
        The duplicate header is then inserted into the array with columnName_COPYnumOccruences. 
        Import-CSV is then used normally with the new column header array as the -header parameter.
        
        .PARAMETER $Path
        The full file path
        e.g. "C:\users\johndoe\desktop\myfile.csv"
        #>
        
            param(
                [Parameter(Mandatory=$true)] [string] $Path
            )
            
            $headerRow = Get-Content $Path | ConvertFrom-String -Delimiter "," | Select-Object -First 1 
            $objectSize = ($headerRow | Get-Member -MemberType NoteProperty | Measure-Object).Count
            $headers = @()
            $duplicates = @{}
        
            for ($i = 1; $i -le $objectSize; $i++){
                if ($headers -notcontains $headerRow."P$i"){
                    $headers += $headerRow."P$i"
                }else{
                    if ($duplicates.$($headerRow."P$i") -gt 0){
                        $duplicates.$($headerRow."P$i")++
                    }else{
                        $duplicates.$($headerRow."P$i") = 1   
                    }
                    $header = $($headerRow."P$i")
                    $header = $header + "_COPY"
                    $header = $header + ($duplicates.$($headerRow."P$i"))
                    $headers += $header
                }
            }
        
            $headerString = ""
            foreach ($item in $headers){$headerString += "'$item',"}
            $headerString = $headerString.Substring(0,$headerString.Length -1)
        
            $data = Invoke-Expression ("Import-Csv '$Path' " + "-Header " + $headerString)
            return $data
        }
    
    

    【讨论】:

      【解决方案3】:

      您可以使用 get-content 加载日期并像这样转换您的数据

      Get-Content "C:\temp\test.csv" | ConvertFrom-String -Delimiter "," | select -Skip 1
      

      短版:

      gc "C:\temp\test.csv" | cfs -D "," | select -Skip 1
      

      如果你不想自动重命名列,你可以像这样手动重命名

      gc "C:\temp\test.csv" | cfs -D "," -PropertyNames head1, head2, head3 | select -Skip 1
      

      【讨论】:

        【解决方案4】:

        这是一个示例,说明如何在代码中无需硬编码列标题名称(即根据 CSV 文件中的列数动态生成通用标题):

        $csvFile = "test.csv"
        
        # Count columns in CSV file
        $columnCount = (Get-Content $csvFile |
          Select-Object -Index 1,2 |
          ConvertFrom-Csv |
          Get-Member -MemberType NoteProperty |
          Measure-Object).Count
        
        # Create list of generic property names (no duplicates)
        $propertyNames = 1..$columnCount |
          ForEach-Object { "Property{0}" -f $_ }
        
        # Get CSV file content, skip header line, and convert from CSV using generic header
        Get-Content $csvFile |
          Select-Object -Skip 1 |
          ConvertFrom-Csv -Header $propertyNames
        

        此解决方案的一个注意事项是 CSV 文件必须至少包含两行数据(不包括标题行)。

        【讨论】:

          猜你喜欢
          • 2019-03-30
          • 2011-03-23
          • 2013-12-29
          • 2017-01-20
          • 1970-01-01
          • 2016-11-27
          • 2019-06-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多