【问题标题】:How to read multiple data sets from one .csv file in powershell如何在powershell中从一个.csv文件中读取多个数据集
【发布时间】:2014-02-05 00:43:13
【问题描述】:

我有一个临时记录器,它(每天)读取多个传感器并将数据保存到单个 .csv 文件中,其中包含每组日期/时间和温度之前的一大堆标题信息。文件看起来像这样:

"readerinfo","onlylistedonce"
"downloadinfo",YYYY/MM/DD 00:00:00
"timezone",-8
"headerstuff","headersuff"

"sensor1","sensorstuff"
"serial#","0000001"
"about15lines","ofthisstuff"
"header1","header2"
datetime,temp
datetime,temp
datetime,temp

"sensor2","sensorstuff"
"serial#","0000002"
"about15lines","ofthisstuff"
"header1","header2"
datetime,temp
datetime,temp
datetime,temp
"downloadcomplete"

我的目标是提取每个传感器的日期/时间和温度数据并将其保存为一个新文件,以便我可以在其上运行一些基本统计数据(hi/lo/avg temp)。 (如果我能根据标题信息中列出的序列号以某种方式识别数据来自哪个传感器,那就太好了,但这比将数据分成组更重要)日期/时间列表的长度随传感器的变化而变化根据记录的时间长短和传感器的数量每天都在变化。即使我可以将传感器数据、标头信息等全部拆分成有传感器的文件,这将是一个好的开始。

【问题讨论】:

    标签: powershell csv


    【解决方案1】:

    这并不完全是传统意义上的 CSV 文件。鉴于您对文件内容的描述,我想您已经知道这一点。

    如果 datetime,temp truly 行中没有任何双引号,根据您的示例数据,那么以下脚本应该可以工作。该脚本是自包含的,因为它内联声明了示例数据。

    重要提示:您需要修改包含$SensorList 变量声明的行。您必须使用传感器名称填充此变量,或者您可以参数化脚本以接受传感器名称数组。

    更新:我更改了要参数化的脚本。

    结果

    脚本运行结果如下:

    1. sensor1.csv(带有相应数据)
    2. sensor2.csv(带有相应数据)
    3. 一些绿色文本将写入 PowerShell 主机,指示当前检测到哪个传感器

    脚本

    脚本的内容应如下所示。将脚本文件保存到文件夹,如c:\test\test.ps1,然后执行。

    # Declare text as a PowerShell here-string
    $Text = @"
    "readerinfo","onlylistedonce"
    "downloadinfo",YYYY/MM/DD 00:00:00
    "timezone",-8
    "headerstuff","headersuff"
    
    "sensor1","sensorstuff"
    "serial#","0000001"
    "about15lines","ofthisstuff"
    "header1","header2"
    datetime,tempfromsensor1
    datetime,tempfromsensor1
    datetime,tempfromsensor1
    
    "sensor2","sensorstuff"
    "serial#","0000002"
    "about15lines","ofthisstuff"
    "header1","header2"
    datetime,tempfromsensor2
    datetime,tempfromsensor2
    datetime,tempfromsensor2
    "downloadcomplete"
    "@.Split("`n");
    
    # Declare the list of sensor names
    $SensorList = @('sensor1', 'sensor2');
    $CurrentSensor = $null;
    
    # WARNING: Clean up all CSV files in the same directory as the script
    Remove-Item -Path $PSScriptRoot\*.csv;
    
    # Iterate over each line in the text file
    foreach ($Line in $Text) {
        #region Line matches double quote
        if ($Line -match '"') {
            # Parse the property/value pairs (where double quotes are present)
            if ($Line -match '"(.*?)",("(?<value>.*)"|(?<value>.*))') {
                $Entry = [PSCustomObject]@{
                    Property = $matches[1];
                    Value = $matches['value'];
                };
                if ($matches[1] -in $SensorList) {
                    $CurrentSensor = $matches[1];
                    Write-Host -ForegroundColor Green -Object ('Current sensor is: {0}' -f $CurrentSensor);
                }
            }        
        }
        #endregion Line matches double quote
        #region Line does not match double quote
        else {
            # Parse the datetime/temp pairs
            if ($Line -match '(.*?),(.*)') {
                $Entry = [PSCustomObject]@{
                    DateTime = $matches[1];
                    Temp = $matches[2];
                };
                # Write the sensor's datetime/temp to its file
                Add-Content -Path ('{0}\{1}.csv' -f $PSScriptRoot, $CurrentSensor) -Value $Line;
            }
        }
        #endregion Line does not match double quote
    }
    

    【讨论】:

      【解决方案2】:

      使用您提供的数据样本,此脚本的输出如下:

      C:\sensoroutput_20140204.csv

      sensor1,datetime,temp
      sensor1,datetime,temp
      sensor1,datetime,temp
      sensor2,datetime,temp
      sensor2,datetime,temp
      sensor2,datetime,temp
      

      我相信这就是您正在寻找的。这里的假设是换行符。 get-content 行正在读取数据并将其分解为“集合”,方法是使用 2 个换行符作为要拆分的分隔符。我选择使用环境的(Windows)换行符。您的源文件可能有不同的换行符。您可以使用 Notepad++ 查看它们是哪些字符,例如\r\n、\n等

      $newline = [Environment]::NewLine
      $srcfile = "C:\sensordata.log"
      $dstpath = 'C:\sensoroutput_{0}.csv' -f (get-date -f 'yyyyMMdd')
      
      # Reads file as a single string with out-string
      # then splits with a delimiter of two new line chars
      $datasets = get-content $srcfile -delimiter ($newline * 2)
      
      foreach ($ds in $datasets) {
        $lines = ($ds -split $newline)                   # Split dataset into lines
        $setname = $lines[0] -replace '\"(\w+).*', '$1'  # Get the set or sensor name
        $lines | % {
          if ($_ -and $_ -notmatch '"') {                # No empty lines and no lines with quotes
            $data = ($setname, ',', $_ -join '')         # Concats set name, datetime, and temp
            Out-File -filepath $dstpath -inputObject $data -encoding 'ascii' -append
          }
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-02-14
        • 2023-02-24
        • 2020-03-16
        • 2013-07-05
        • 2017-05-17
        • 2015-08-23
        • 2023-03-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多