Powershell 将导入的 CSV 导出为没有分隔符的固定记录长度?

Powershell export an imported CSV as fixed record length with no delimiter?

我有一个非常标准的 CSV 文件,它看起来像这样:

heading1,heading2,heading3
aaaaaaaaa,bb,ccccccc
d,eeeeeeee,ff
gggggggg,hh,iiiiiiiiiii

此文件已使用 import-csv 导入到 object。我现在想将 object 导出到一个具有固定记录长度且没有定界符且没有 table headers 的文件。如果导入的值对于固定文件来说太长,则应将其截断。如果导入的值太短,值应该左对齐并用空格填充。

假设宽度为:

heading1 is 5
heading2 is 2 
heading3 is 10

基本上输出应该是这样的:

aaaaabbccccccc   
d    eeff        
ggggghhiiiiiiiiii

请注意第 3 列中值末尾的空格。

算法应该不会完全低效 - 它将用于转换 300MB 的 csv 文件。

我在 Whosebug 上搜索并用谷歌搜索了一段时间,可以使用自定义 table 格式和 format-table 等解决方案找到一些相关问题,但这些解决方案似乎并不容易适应table 对我来说这个具体问题。

至于原因:这种非常 ugly/unusual 的格式是小众 COTS 软件所必需的。

我真的不知道你为什么要这样做,但嘿,你这样做很公平。

我想我明白你想做什么,这会给你一个数组,每一行都是将数据处理成你想要的格式,然后你可以将该数组循环到 txt 文件、日志文件等你要。

$spacerCSVFile = "spacers.csv"
$prinspacerCSV = Import-Csv $spacerCSVFile -header "1","2","3"
$processedArray = New-Object System.Collections.Generic.List[System.Object]
foreach($row in $prinspacerCSV) {
    if ($row.1 -like "heading*") {
        # do nothing for headings
    } else {
        $item1 = $row.1
        $item2 = $row.2
        $item3 = $row.3

        while ($item1.length -lt 6) {
            $item1 += " "
        }
        while ($item2.length -lt 3) {
            $item2 += " "
        }
        while ($item3.length -lt 11) {
            $item3 += " "
        }
        if ($item1.length -gt 5) {
            $item1 = $item1.substring(0,5)
        }
        if ($item2.length -gt 2) {
            $item2 = $item2.substring(0,2)
        }
        if ($item3.length -gt 10) {
           $item3 = $item3.substring(0,10)
        }
        $processedArray += ,"$item1$item2$item3"
    }
}
foreach ($item in $processedArray) {
    write-host $item
}

不过,我建议您值得一试,先准备好一些代码,因为堆栈溢出的想法是帮助您的代码,而不是提供它。

这非常丑陋,可能比它需要的更复杂,但据我所知这是可行的。

希望这能给你一个想法或者这只是帮助

$file = "C:\Logs\Test.csv"

$data = Import-Csv $file

$properties = $data | 
              Get-Member | 
              Where-Object MemberType -EQ NoteProperty | 
              Select Name

foreach ($line in $data){

    [string]$dataout = $null

    foreach ($property in $properties) {
        $dataout = $dataout + $line.($property.Name)
    }

    if($dataout.Length -eq 20){
        $dataout
    }
    elseif ($dataout.Length -lt 20) {        
        Do{
            $dataout = $dataout + " "            
        }
        Until($dataout.Length -eq 20)
        $dataout        
    }
    else {
        $dataout = ($dataout.Substring(0,20))
        $dataout        
    }
}
## Q:\Test18\SO_51265871.ps1
$SPC = '                           ';
Import-Csv .\Input.csv | 
  ForEach-Object {"[{0}{1}{2}]" -f ($_.heading1+$SPC).Substring(0,5),
                                   ($_.heading2+$SPC).Substring(0,2),
                                   ($_.heading3+$SPC).Substring(0,10)
  } | Set-Content .\Output.rec

格式字符串中的[]只是为了显示包含尾随空格的长度。

示例输出:

PS> Get-Content .\Output.rec
[aaaaabbccccccc   ]
[d    eeff        ]
[ggggghhiiiiiiiiii]

编辑:一个更通用的变体,从数组馈送列宽 - 相同的输出

$CW = @(5,2,10) # array CW = ColumnWidth
Import-Csv .\Input.csv | ForEach-Object { $i = 0
  "[{0}{1}{2}]" -f `
    ($_.heading1).PadRight($CW[$i]).Substring(0,$CW[$i++]),
    ($_.heading2).PadRight($CW[$i]).Substring(0,$CW[$i++]),
    ($_.heading3).PadRight($CW[$i]).Substring(0,$CW[$i])
  } #| Set-Content .\Output.rec