【问题标题】:PS Script is exporting an empty CSVsPS 脚本正在导出一个空的 CSV
【发布时间】:2018-12-18 17:08:08
【问题描述】:

我很想了解为什么这个脚本没有按预期工作。这是一个简单的脚本,我尝试在其中导入 CSV,选择我想要的几列,然后导出 CSV 并复制自身。 (基本上我们已经存档了数据,由于内存大小限制,我只需要来自另一个项目的几列)。这个脚本非常简单,显然它与它在不起作用时引起的挫败感成反比......现在最终结果是我最终得到一个空的 csv 而不是只包含我选择的列的 csv使用 Select-Object。

$RootPath = "D:\SomeFolder"

$csvFilePaths = Get-ChildItem $RootPath -Recurse -Include *.csv | 
    ForEach-Object{
        Import-CSV $_ |
        Select-Object Test_Name, Test_DataName, Device_Model, Device_FW, Data_Avg_ms, Data_StdDev | 
        Export-Csv $_.FullName -NoType -Force
}

【问题讨论】:

    标签: powershell csv select-object export-csv


    【解决方案1】:

    除非您将输入文件预先完整地读入内存,否则您无法在给定管道中安全地读取和写回同一文件。 p>

    具体来说,Import-Csv file.csv | ... | Export-Csv file.csv 之类的命令会擦除file.csv 的内容。

    最简单的解决方案是将读取输入文件的命令括在(...)中,但请注意:

    • 文件的内容(转换为对象)必须适合整个内存

    • 如果在所有(转换的)对象都写回文件之前中断管道,则存在数据丢失的轻微风险

    应用于您的命令:

    $RootPath = "D:\SomeFolder"
    
    Get-ChildItem $RootPath -Recurse -Include *.csv -OutVariable csvFiles | 
        ForEach-Object{
            (Import-CSV $_.FullName) | # NOTE THE (...)
              Select-Object Test_Name, Test_DataName, Device_Model, Device_FW, 
                            Data_Avg_ms, Data_StdDev | 
                Export-Csv $_.FullName -NoType -Force
    }
    

    请注意,我使用-OutVariable csvFiles 来收集输出变量$csvFiles 中的CSV 文件信息对象。您尝试通过$csvFilePaths = ... 收集文件路径不起作用,因为它尝试收集Export-Csv 输出,但Export-Csv 不产生任何输出。

    另外,为了安全起见,我已将 Import-Csv 参数从 $_ 更改为 $_.FullName 以确保 Import-Csv 找到输入文件(因为遗憾的是,文件信息对象 $_ 已绑定作为一个字符串有时会扩展为仅仅是文件名)。


    更安全的解决方案首先输出到临时文件,并且(仅)在成功完成后替换原始文件。

    无论采用哪种方法,替换文件都将具有默认文件属性和权限;如果原始文件具有您想要保留的特殊属性和/或权限,您必须明确地重新创建它们。

    【讨论】:

    • 谢谢!我只需要一种快速而肮脏的方法来减小这些文件的大小,我并没有修改实际的档案,而是我为这个项目制作的一份副本,所以我不太担心防错或意外的数据丢失,因为数据已存档并可轻松检索。我采用了一种更直接的方法,即在我的 for 循环中声明一个执行 Import-Csv 函数的变量,但您的解决方案肯定更优雅。其中一种情况是,当给出答案时,我只能说“duh”。对我自己...
    【解决方案2】:

    正如 Matt 所评论的,您的最后一个 $PSItem ($_) 不再与 Get-ChildItem 相关,而是与没有 FullName 属性的 Select-Object cmdlet 相关

    您可以使用不同的 foreach 方法:

    $RootPath = "D:\SomeFolder"
    $csvFilePaths = Get-ChildItem $RootPath -Recurse -Include *.csv
    
    foreach ($csv in $csvFilePaths)
    {
    Import-CSV $csv.FullName |
    Select-Object Test_Name,Test_DataName,Device_Model,Device_FW,Data_Avg_ms,Data_StdDev | 
    Export-Csv $csv.FullName -NoType -Force
    }
    

    或者保留您的代码,添加包含 csv 路径的 $CsvPath 变量并稍后使用它:

    $RootPath = "D:\SomeFolder"
    Get-ChildItem $RootPath -Recurse -Include *.csv | ForEach-Object{
    $CsvPath = $_.FullName
    Import-CSV $CsvPath |
    Select-Object Test_Name,Test_DataName,Device_Model,Device_FW,Data_Avg_ms,Data_StdDev | 
    Export-Csv $CsvPath -NoType -Force
    }
    

    【讨论】:

    • 感谢大家的帮助,不幸的是,这些建议都不起作用。每当我导出 CSV 时,它都会导出为空 CSV。有趣的是,我从更直接的 ForEach 循环开始,然后将管道转移到 ForEach_Object cmdlet,因为 ForEach 方法产生了相同的错误。这让我想把我的头发拉出来......
    • 不,$_ 仍然指的是Get-ChildItem 输入对象,因为它没有在脚本块中使用。真正的问题是在单个管道中读取和写入同一个文件(没有先完整读取文件)。
    【解决方案3】:

    所以我想通了。我试图直接通过 Import-Csv cmdlet 进行管道传输,而不是在 o.g. 中将其声明为变量。代码。这是代码 sn-p 可以完成我想要完成的工作。我之前试图直接在 Import-Csv cmdlet 中进行管道传输,我只需要声明一个使用 Import-Csv cmdlet 作为其定义的变量,然后将该变量通过管道传递给 Select-Object,然后是 Export-Csv cmdlet。谢谢大家的帮助,不胜感激!

    $RootPath = "\someDirectory\"
    $CsvFilePaths = @(Get-ChildItem $RootPath -Recurse -Include *.csv)
    $ColumnsWanted = @('Test_Name','Test_DataName','Device_Model','Device_FW','Data_Avg_ms','Data_StdDev')
    for($i=0;$i -lt $CsvFilePaths.Length; $i++){
      $csvPath = $CsvFilePaths[$i]
      Write-Host $csvPath
      $importedCsv = Import-CSV $csvPath 
      $importedCsv | Select-Object $ColumnsWanted | Export-CSV $csvPath -NoTypeInformation
    }
    

    【讨论】:

      猜你喜欢
      • 2011-01-28
      • 2018-08-21
      • 2021-05-13
      • 1970-01-01
      • 2021-01-04
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 2015-07-16
      相关资源
      最近更新 更多