将固定宽度的 txt 文件转换为 CSV / set-content 或 out-file -append?
Convert fixed width txt file to CSV / set-content or out-file -append?
输入文件是固定宽度的txt文件。我的客户通常在 Excel 中打开它并手动指定分栏符。我希望用逗号替换某些空格,以便我可以解析为 CSV 并保存为 XLS 或其他格式。
$columBreaks = 20, 35, 50, 80, 100, 111, 131, 158, 161, 167, 183
[array]::Reverse($columBreaks) #too lazy to re-write array after finding out I need to iterate in reverse
$files = get-childitem ./ |where-object {$_.Name -like "FileFormat*.txt"}
foreach($file in $files)
{
$name = $file.Name.split(".")
$csvFile = $name[0]+".csv"
if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed
{
$text = (gc $file)
foreach ($line in $text)
{
foreach ($pos in $columBreaks)
{
#$line.Substring($char-1,3).replace(" ", ",")
$line = $line.Insert($pos,",")
#out-file -append?
}
}
}
#set-content?
}
那么将这些内容写出来最有效的方法是什么?我曾希望使用 set-content,但我认为这是不可能的,因为我们正在逐行处理,所以我认为我要么必须为 set-content 构建一个行数组,要么使用写出 -为每次迭代追加。有没有更有效的方法来做到这一点?
Set-Content 通过一些小的调整应该可以正常工作。这是它应该如何工作的示例(这是外部 foreach 循环中的所有内容):
$csvFile = $file.BaseName
if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed
{
(gc $file | foreach {
$_.Insert($columBreaks[0],",").Insert($columBreaks[1],",").Insert($columBreaks[2],",").`
Insert($columBreaks[3],",").Insert($columBreaks[4],",").Insert($columBreaks[5],",").`
Insert($columBreaks[6],",").Insert($columBreaks[7],",").Insert($columBreaks[8],",").`
Insert($columBreaks[9],",").Insert($columBreaks[10],",")
}) | set-content $csvFile #note parenthesis around everything that gets piped to set-content
}
顺便说一下,您可以使用 $file.BaseName
获取不带扩展名的文件名,而不是在“.”上拆分文件名:
$csvFile = $file.BaseName + ".csv"
这是工作代码。修复了一些错误。
CD 'C:\FOLDERPATH\'
$filter = "FILE_NAME_*.txt"
$columns = 11,22,32,42,54
# DO NOT NEED TO REVERSE [array]::Reverse($columns) #too lazy to re-write array after finding out I need to iterate in reverse
$files = get-childitem ./ |where-object {$_.Name -like $filter}
$newDelimiter = '|'
foreach($file in $files)
{
$file
$csvFile = 'C:\FOLDERPATH\NEW_' + $file.BaseName + '.txt'
if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed
{
$content | ForEach {
$line = $_
$counter = 0
$columns | ForEach {
$line = $line.Insert($_+$counter, $newDelimiter)
$counter = $counter + 1
}
$line = $line.Trim($newDelimiter)
$line
} | set-content $csvFile
}
}
我认为这经常出现。这是一个实际上过火并将固定宽度文件转换为对象的示例。然后将其导出到 csv 很简单。这也适用于转换遗留命令,如 netstat。
$cols = 0,19,38,59,81,97,120,123 # fake extra column at the end, assumes all rows are that wide, padded with spaces
$colsfile = 'columns.txt'
$csvfile = 'cust.csv'
$firstline = get-content $colsfile | select -first 1
$headers = for ($i = 0; $i -lt $cols.count - 1; $i++) {
$firstline.substring($cols[$i], $cols[$i+1]-$cols[$i]).trim()
}
# string Substring(int startIndex, int length)
Get-Content $colsfile | select -skip 1 | ForEach {
$hash = [ordered]@{}
for ($i = 0; $i -lt $headers.length; $i++) {
$value = $_.substring($cols[$i], $cols[$i+1]-$cols[$i]).trim()
$hash += @{$headers[$i] = $value}
}
[pscustomobject]$hash
} | export-csv $csvfile
输入文件是固定宽度的txt文件。我的客户通常在 Excel 中打开它并手动指定分栏符。我希望用逗号替换某些空格,以便我可以解析为 CSV 并保存为 XLS 或其他格式。
$columBreaks = 20, 35, 50, 80, 100, 111, 131, 158, 161, 167, 183
[array]::Reverse($columBreaks) #too lazy to re-write array after finding out I need to iterate in reverse
$files = get-childitem ./ |where-object {$_.Name -like "FileFormat*.txt"}
foreach($file in $files)
{
$name = $file.Name.split(".")
$csvFile = $name[0]+".csv"
if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed
{
$text = (gc $file)
foreach ($line in $text)
{
foreach ($pos in $columBreaks)
{
#$line.Substring($char-1,3).replace(" ", ",")
$line = $line.Insert($pos,",")
#out-file -append?
}
}
}
#set-content?
}
那么将这些内容写出来最有效的方法是什么?我曾希望使用 set-content,但我认为这是不可能的,因为我们正在逐行处理,所以我认为我要么必须为 set-content 构建一个行数组,要么使用写出 -为每次迭代追加。有没有更有效的方法来做到这一点?
Set-Content 通过一些小的调整应该可以正常工作。这是它应该如何工作的示例(这是外部 foreach 循环中的所有内容):
$csvFile = $file.BaseName
if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed
{
(gc $file | foreach {
$_.Insert($columBreaks[0],",").Insert($columBreaks[1],",").Insert($columBreaks[2],",").`
Insert($columBreaks[3],",").Insert($columBreaks[4],",").Insert($columBreaks[5],",").`
Insert($columBreaks[6],",").Insert($columBreaks[7],",").Insert($columBreaks[8],",").`
Insert($columBreaks[9],",").Insert($columBreaks[10],",")
}) | set-content $csvFile #note parenthesis around everything that gets piped to set-content
}
顺便说一下,您可以使用 $file.BaseName
获取不带扩展名的文件名,而不是在“.”上拆分文件名:
$csvFile = $file.BaseName + ".csv"
这是工作代码。修复了一些错误。
CD 'C:\FOLDERPATH\'
$filter = "FILE_NAME_*.txt"
$columns = 11,22,32,42,54
# DO NOT NEED TO REVERSE [array]::Reverse($columns) #too lazy to re-write array after finding out I need to iterate in reverse
$files = get-childitem ./ |where-object {$_.Name -like $filter}
$newDelimiter = '|'
foreach($file in $files)
{
$file
$csvFile = 'C:\FOLDERPATH\NEW_' + $file.BaseName + '.txt'
if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed
{
$content | ForEach {
$line = $_
$counter = 0
$columns | ForEach {
$line = $line.Insert($_+$counter, $newDelimiter)
$counter = $counter + 1
}
$line = $line.Trim($newDelimiter)
$line
} | set-content $csvFile
}
}
我认为这经常出现。这是一个实际上过火并将固定宽度文件转换为对象的示例。然后将其导出到 csv 很简单。这也适用于转换遗留命令,如 netstat。
$cols = 0,19,38,59,81,97,120,123 # fake extra column at the end, assumes all rows are that wide, padded with spaces
$colsfile = 'columns.txt'
$csvfile = 'cust.csv'
$firstline = get-content $colsfile | select -first 1
$headers = for ($i = 0; $i -lt $cols.count - 1; $i++) {
$firstline.substring($cols[$i], $cols[$i+1]-$cols[$i]).trim()
}
# string Substring(int startIndex, int length)
Get-Content $colsfile | select -skip 1 | ForEach {
$hash = [ordered]@{}
for ($i = 0; $i -lt $headers.length; $i++) {
$value = $_.substring($cols[$i], $cols[$i+1]-$cols[$i]).trim()
$hash += @{$headers[$i] = $value}
}
[pscustomobject]$hash
} | export-csv $csvfile