导入Csv,更改1个字段,然后导出

时间:2018-11-27 00:31:53

标签: powershell csv

我具有以下格式的数据(制表符分隔):

Id      Dates                        Number
5       01-01-18<space><tab>         19
5       01-01-18 02-03-18            19
5       01-01-18 02-03-18 03-02-18   19
37      07-09-18                     19
37      07-09-18 07-15-18            19
37      07-09-18 07-15-18 07-28-18   18.1
41      03-15-18                     19
41      03-15-18 04-15-18            19
41      03-15-18 04-15-18 05-15-18   36.5

第二个字段Dates实际上是一个带有尾随空格的数组(以空格分隔)。

在将第二个字段修改为仅包括最后日期之后,我需要将其导入到PowerShell中并导出到新的CSV文件:

Id      Dates      Number
5       01-01-18   19
5       02-03-18   19
5       03-02-18   19
37      07-09-18   19
37      07-15-18   19
37      07-28-18   18.1
41      03-15-18   19
41      04-15-18   19
41      05-15-18   36.5

在遍历记录之后,除了错误外,我什么也没得到(因此,我没有与此一起发布的半工作代码)。

CSV文件最多可以包含100,000条记录。


到目前为止,我已经知道了:

$ImportDir = "input_dir"
$ExportDir = "output_dir"

# We only want the files generated yesterday
$Date = (Get-Date).AddDays(-1).ToString('yyyyMMdd')

Add-Content ($ExportDir + "blahblah_" + $Date + ".txt") "Id`tDate`tValue"

Get-ChildItem $ImportDir -Filter *_blahblah_$Date.txt | ForEach-Object {
    $File = [System.IO.File]::ReadAllText((Resolve-Path $_.FullName))

    foreach ($RecordSet In $File) {
        $RecordSet.TrimEnd() -Replace "(\d+?)`t.*(\d\d-\d\d-\d\d) `t(\d+?.\d+?) `t", "`$1`t`$2`t`$3" |
            #Select-Object -Skip 1 |
            Add-Content ($ExportDir + "blahblah_" + $Date + ".txt")
    }
}

我之所以改用[System.IO.File]是因为它比-ReadCount快,而-ReadCount则以某种方式丢失了记录。最后我需要弄清楚的是如何跳过每个文件的第一行(基本上我正在许多文件上执行此正则表达式,并且需要删除标题)。似乎我所做的任何事情都会导致脚本无法正常工作。

2 个答案:

答案 0 :(得分:2)

即使我认为您将需要对大型文件使用StreamReader,这也是我对Import-CSV的使用方式。请注意,它实际上是列中的最后日期,不一定是按时间顺序的最后日期[咧嘴] ...

# fake reading in a CSV file with tab delimiters
#    in real life, use Import-CSV
# each "Dates" column has a trailing <space>
$InStuff = @'
Id  Dates   Number
5   01-01-18    19
5   01-01-18 02-03-18   19
5   01-01-18 02-03-18 03-02-18  19
37  07-09-18    19
37  07-09-18 07-15-18   19
37  07-09-18 07-15-18 07-28-18  18.1
41  03-15-18    19
41  03-15-18 04-15-18   19
41  03-15-18 04-15-18 05-15-18  36.5
'@ | ConvertFrom-Csv -Delimiter "`t"

$LastDateOnly = foreach ($IS_Item in $InStuff)
    {
    [PSCustomObject]@{
        ID = $IS_Item.Id
        Date = $IS_Item.Dates.Trim().Split(' ')[-1]
        Number = $IS_Item.Number
        }
    }

$LastDateOnly

输出...

ID Date     Number
-- ----     ------
5  01-01-18 19    
5  02-03-18 19    
5  03-02-18 19    
37 07-09-18 19    
37 07-15-18 19    
37 07-28-18 18.1  
41 03-15-18 19    
41 04-15-18 19    
41 05-15-18 36.5  

答案 1 :(得分:2)

如果要将数据视为纯文本,并且CSV确实按照指定的格式进行了格式化(没有引号或其他内容),则可以在每行上执行正则表达式替换以获取所需的数据,并且应该比较快。我可以一次处理1000条记录,但是您可以尝试使用-ReadCount数字来查看是否可以提高性能。较高的数字会占用更多的内存,但应该使其运行更快。

ForEach($RecordSet in (Get-Content C:\Path\To\File.csv -ReadCount 1000)){
    $RecordSet -replace "(\S+?)`t.*(\d\d-\d\d-\d\d) `t(.*)$","`$1`t`$2`t`$3" | Add-Content C:\Path\To\NewFile.csv
}