首页 > 解决方案 > 读取 1 行制表符分隔数据并导出为“+”分隔时生成的空 CSV 文件

问题描述

(PowerShell)脚本的目标是获取一个制表符分隔的文本文件,删除标题行,将分隔符更改为“+”,添加自定义标题记录并在文件底部添加一个摘要(页脚)行数据记录数的计数。最后,文件扩展名需要替换为序号。

当原始文件包含超过 1 行时,结果符合要求,但当只有一行(标题加 1 数据行)时,输出文件为空。

$dir = "C:\Temp\Data"
$file = "rand1"

$sequencefile = "C:\temp\Sequential\DoNotDeleteSequence.txt"

$sequencenumber = (Get-Content $sequencefile)
$newsequencenumber = ($sequencenumber/1) + 1

Clear-Content $sequencefile
Add-Content $sequencefile $newsequencenumber

$backslash = "\"
$ext = ".txt"
$filename = $dir + $backslash + $file + $ext
$text = "TRAILER = "
$dateText = Get-Date -Format d
$Header1 = "HEADER="
$Header2 = "+PSTG"
$HeaderText = $Header1 + $dateText + $Header2

$tempfile1 = "step1" 
$tempfile2 = "step2" 
$tempfile3 = "step3" 
$tempfile4 = "step4" 

$temppstg = "PSTG_NCDLPSTG."

$stepfile1 = $dir + $backslash + $tempfile1 + $ext
$stepfile2 = $dir + $backslash + $tempfile2 + $ext
$stepfile3 = $dir + $backslash + $tempfile3 + $ext
$stepfile4 = $dir + $backslash + $tempfile4 + $ext

$pstgfile = $dir + $backslash + $temppstg + $newsequencenumber

(Get-Content $filename).Replace("+", '') | Set-Content $stepfile1
(Get-Content $stepfile1) | select -Skip 1 | Set-Content $stepfile2
Import-Csv $stepfile2 -Delimiter "`t" | Export-Csv $stepfile3 -Delimiter "+" -NoTypeInformation
Set-Content $stepfile4 $HeaderText
(Get-Content $stepfile3).Replace("""", '') | Add-Content $stepfile4
$records = Import-Csv $stepfile4 | Measure-Object | Select-Object -Expand Count

$textToWrite = $text + $records

Add-Content $stepfile4 $textToWrite

Rename-Item $stepfile4 $pstgfile

我创建了 2 个测试原始文件(制表符分隔)。

C:\Temp\Data\rand1.txt包含

标题行
记录 1 数据 1

C:\Temp\Data\rand2.txt包含

标题行
记录 1 数据 1
记录 2 数据 2

rand2.txt通过代码时,结果是

标题=25/03/2019+PSTG
记录1+数据1
记录2+数据2
拖车 = 2

处理时rand1.txt,结果为

标题=25/03/2019+PSTG
拖车 = 0

标签: powershellpowershell-4.0

解决方案


以下两个处理步骤导致您观察到的行为:

(Get-Content $stepfile1) | select -Skip 1 | Set-Content $stepfile2
Import-Csv $stepfile2 -Delimiter "`t" | Export-Csv $stepfile3 -Delimiter "+" -NoTypeInformation

要了解发生了什么,您只需查看各个处理步骤即可。我正在并排显示文件rand1.txt(左)和(右)的输入和输出,以说明正在发生的事情。rand2.txt

  1. (Get-Content $stepfile1) | select -Skip 1 | Set-Content $stepfile2

    输入:

    标题行 标题行
    记录 1 数据 1 记录 1 数据 1
                                  记录 2 数据 2
    

    输出:

    记录 1 数据 1 记录 1 数据 1
                                  记录 2 数据 2
    

    此步骤将删除标题行,为 保留一行,为 保留rand1.txt两行rand2.txt。这本身并不是您观察到的问题的根本原因,但它为真正的罪魁祸首奠定了基础。

  2. Import-Csv $stepfile2 -Delimiter "`t" | Export-Csv $stepfile3 -Delimiter "+" -NoTypeInformation

    输入:

    记录 1 数据 1 记录 1 数据 1
                                  记录 2 数据 2
    

    输出:

                                  记录1+数据1
                                  记录2+数据2
    

    由于方式和工作原因,此步骤使您没有 的输出rand1.txt,但都有 的记录。rand2.txtImport-CsvExport-Csv

    Import-Csv将分隔文件的行转换为自定义对象,并将每行的字段转换为这些对象的属性,从输入文件的第一行获取这些属性的名称。

    Export-Csv与其同级 cmdlet 完全相反:它将自定义对象列表转换为数据行,并将对象属性的值转换为数据行的字段。列表中第一个对象的属性名称决定了哪些属性被导出,并且还形成了输出文件的标题行。

    由于rand1.txt只有一行(即只有标题行),在导入时不会创建任何对象,因为没有数据,因此没有数据可以导出回文件。rand2.txt另一方面,有两行,因此在导入时,您将获得一个具有以下结构的对象(以 JSON 表示法):

    {
      "Record1": "Record2",
      "Data1": "Data2"
    }
    

    然后将其转换回标题行Record1+Data1和数据行Record2+Data2

后续步骤仅向您创建的中间文本文件添加新的标题行。如果您在使用之前没有删除标头Import-Csv,或者一开始就没有使用*-Csvcmdlet,则不会发生此问题。

话虽如此,您的整个处理过程太复杂了。您只需以下几行即可获得所需的结果(为简洁起见,省略了一些变量定义):

$filename = Join-Path $dir "${file}${ext}"

$records = (Get-Content $filename).Replace('+', '').Replace("`t", '+') |
           Select-Object -Skip 1

$newsequencenumber = [int](Get-Content $sequencefile) + 1
$pstgfile = Join-Path $dir "PSTG_NCDLPSTG.${newsequencenumber}"

"HEADER=$(Get-Date -Format d)+PSTG" | Set-Content $ptsgfile
$records | Add-Content $ptsgfile
"TRAILER = $($records.Count)" | Add-Content $ptsgfile

推荐阅读