簡體   English   中英

使用 powershell 將 JS 格式的 csv 轉換為帶分隔符的 CSV

[英]Convert JS format csv to a delimited CSV using powershell

我有一個示例 csv 文件,並嘗試使用 powershell 轉換為分隔格式的 csv。 對於時間戳部分,默認存儲為秒,想知道能不能轉成"hh:mm"

不太確定我應該從哪里開始。

感謝幫助!

樣本.csv

{
   "Body" : {
      "inverter/1" : {
         "Data" : {
            "Current_DC_String_1" : {
               "Unit" : "A",
               "Values" : {
                  "0" : 0,
                  "300" : 0,
                  "600" : 0,
                  "900" : 0
               },
               "_comment" : "channelId=66050"
            },
            "Current_DC_String_2" : {
               "Unit" : "A",
               "Values" : {
                  "0" : 0,
                  "300" : 0,
                  "600" : 0,
                  "900" : 0
               },
               "_comment" : "channelId=131586"
            },
            "EnergyReal_WAC_Sum_Produced" : {
               "Unit" : "Wh",
               "Values" : {
                  "0" : 0,
                  "300" : 0,
                  "600" : 0,
                  "900" : 0
               },
               "_comment" : "channelId=67830024"
            },
            "Voltage_DC_String_1" : {
               "Unit" : "V",
               "Values" : {
                  "0" : 7.3000000000000007,
                  "300" : 7.3000000000000007,
                  "600" : 7.9000000000000004,
                  "900" : 7.7000000000000002
               },
               "_comment" : "channelId=66049"
            },
            "Voltage_DC_String_2" : {
               "Unit" : "V",
               "Values" : {
                  "0" : 4.2000000000000002,
                  "300" : 4.2000000000000002,
                  "600" : 4.5,
                  "900" : 4.4000000000000004
               },
               "_comment" : "channelId=131585"
            }
         },
         "DeviceType" : 233,
         "End" : "2020-03-11T23:59:59+11:00",
         "NodeType" : 97,
         "Start" : "2020-03-11T00:00:00+11:00"
      },
      "inverter/2" : {
         "Data" : {
            "Current_DC_String_1" : {
               "Unit" : "A",
               "Values" : {
                  "0" : 0,
                  "300" : 0,
                  "600" : 0,
                  "900" : 0
               },
               "_comment" : "channelId=66050"
            },
            "Current_DC_String_2" : {
               "Unit" : "A",
               "Values" : {
                  "0" : 0,
                  "300" : 0,
                  "600" : 0,
                  "900" : 0
               },
               "_comment" : "channelId=131586"
            },
            "EnergyReal_WAC_Sum_Produced" : {
               "Unit" : "Wh",
               "Values" : {
                  "0" : 0,
                  "300" : 0,
                  "600" : 0,
                  "900" : 0
               },
               "_comment" : "channelId=67830024"
            },
            "Voltage_DC_String_1" : {
               "Unit" : "V",
               "Values" : {
                  "0" : 6.7000000000000002,
                  "300" : 7,
                  "600" : 6.8000000000000007,
                  "900" : 7.2000000000000002
               },
               "_comment" : "channelId=66049"
            },
            "Voltage_DC_String_2" : {
               "Unit" : "V",
               "Values" : {
                  "0" : 2.2000000000000002,
                  "300" : 2.3000000000000003,
                  "600" : 2.2000000000000002,
                  "900" : 2.2000000000000002
               },
               "_comment" : "channelId=131585"
            }
         },
         "DeviceType" : 233,
         "End" : "2020-03-11T23:59:59+11:00",
         "NodeType" : 98,
         "Start" : "2020-03-11T00:00:00+11:00"
      }
   },
   "Head" : {
      "RequestArguments" : {
         "Query" : "Inverter+SensorCard+Meter",
         "Scope" : "System"
      },
      "Status" : {
         "Code" : 0,
         "Reason" : "",
         "UserMessage" : ""
      },
      "Timestamp" : "2020-03-11T01:00:03+11:00"
   }
}

轉換默認時間戳的預期結果

在此處輸入圖片說明

或者,如果可能,可以在轉換時間前添加從“開始”解析的日期“2020-03-11”:“2020-03-11T00:00:00+11:00”,為每一行制作 DateTimestamp。

在此處輸入圖片說明

假設您的數據實際上是一個 JSON 文件,而不是一個 CSV 文件,您可以嘗試以下方法。 如果基本上使用-AsHashTable開關使用ConvertFrom-Json將 JSON 文件轉換為System.Collections.Hashtable對象。 您可以從循環遍歷哈希或在 PowerShell 中使用數組閱讀如何遍歷哈希表屬性。

然后,您可以獲取System.Management.Automation.PSCustomObject行和管道到Export-Csv ,這將創建 CSV 文件。 此外,您可以使用[System.Timespan]::FromSeconds()獲取時間跨度,它將總秒數轉換為System.Timespan類型的對象並使用System.TimeSpan.ToString()格式為hh:mm 有關時間跨度格式的更多信息,您可以查看在 PowerShell 中將秒轉換為 hh:mm:ss,fff 格式

作為額外的清理步驟,我還刪除了帶有Set-Content"引號。如果您希望"保留在您的文件中,則沒有必要這樣做。

$json = Get-Content -Path .\sample.json | ConvertFrom-Json -AsHashtable

$json.Body.GetEnumerator() | ForEach-Object {
    $inverter = $_.Key

    $_.Value.Data.GetEnumerator() | ForEach-Object {
        $value = $_.Key

        $_.Value.Values.GetEnumerator() | ForEach-Object {
            [PSCustomObject]@{
                Inverter = "$inverter $value"
                Second = [timespan]::FromSeconds($_.Key).ToString("hh\:mm")
                Value = $_.Value
            }
        }
    }
} | Export-Csv -Path .\sample.csv
# Use NoTypeINformation to remove #TYPE from headers in < Powershell 6

Set-Content -Path .\sample.csv -Value ((Get-Content -Path .\sample.csv) -replace '"')

樣本.csv

Inverter,Second,Value
inverter/1 Current_DC_String_2,00:05,0
inverter/1 Current_DC_String_2,00:10,0
inverter/1 Current_DC_String_2,00:15,0
inverter/1 Current_DC_String_2,00:00,0
inverter/1 Current_DC_String_1,00:05,0
inverter/1 Current_DC_String_1,00:10,0
...

性能改進

正如mklement0解釋的那樣,當使用 .NET 類型或[PSCustomObject] ,成員枚舉比使用管道快得多。 您可以從這個有用的答案中找到更多信息。

下面是可以使用foreach枚舉而不是Foreach-Object進行的改進的簡單用法。

$json = Get-Content -Path .\sample.json | ConvertFrom-Json -AsHashtable

$csvRows = @()

foreach ($inverter in $json.Body.GetEnumerator()) {

    foreach ($outerValue in $inverter.Value.Data.GetEnumerator()) {

        foreach ($innerValue in $outerValue.Value.Values.GetEnumerator()){
            $csvRowData = [PSCustomObject]@{
                Inverter = "$($inverter.Key) $($outerValue.Key)"
                Second = [timespan]::FromSeconds($innerValue.Key).ToString("hh\:mm")
                Value = $innerValue.Value
            }

            $csvRows += $csvRowData;
        }
    }
}

$csvRows | Export-Csv -Path .\sample.csv

Set-Content -Path .\sample.csv -Value ((Get-Content -Path .\sample.csv) -replace '"')

您的輸入文件是 JSON 文件,而不是CSV文件。

為了將其對象圖展平為您需要的 CSV 行列結構,需要嵌套循環:

# Parse the JSON file into custom objects.
$fromJson = Get-Content -Raw file.json | ConvertFrom-Json

& {
  foreach ($inverter in $fromJson.Body.psobject.Properties.Name) {
    $date =  $fromJson.Body.$inverter.Start
    if ($date -is [datetime]) { $date = $date.ToString('yyyy-MM-dd') }
    else                      { $date = ($date -csplit 'T')[0] }
    foreach ($measurement in $fromJson.Body.$inverter.Data.psobject.Properties.Name) {
      foreach ($valueProp in $fromJson.Body.$inverter.Data.$measurement.Values.psobject.Properties) {
        [pscustomobject] @{
          Inverter  = "$inverter $measurement"
          TimeStamp = $date + ' ' + 
                      [timespan]::FromSeconds([int] $valueProp.Name).ToString('hh\:mm')
          Value     = $valueProp.Value
        }
      }
    }
  } 
} | ConvertTo-Csv  # output CSV data as an array of *strings*; 
                   # to save to a *file*, use something like:
                   # Export-Csv -NoTypeInformation out.csv

請注意.psobject.Properties如何用於反映給定對象的屬性; .psobject是任何對象上可用的通常隱藏的屬性,它比Get-Member cmdlet 更方便、更快速地提供反射信息。

另請注意ConvertFrom-Json如何解析 JSON 中的時間戳取決於 PowerShell 版本(版本):

  • Windows PowerShell將它們解析為strings ,因此將字符串按T拆分並采用它之前的內容就足夠了。

  • PowerShell [Core]將它們解析為[datetime]實例,以本地時間表示,因此只有當本地時區與 JSON 值中的 UTC 偏移量所暗示的時區相同時,它們才能保證產生相同的日歷日( +11:00 )。


可選閱讀:性能考慮

請注意在管道中使用嵌套的foreach循環而不是使用ForEach-Object cmdlet以獲得更好的性能。 有關背景信息,請參閱此答案

然而,對於可能無關緊要的小輸入文件,以及RoadRunner 有用的基於哈希表的替代方案,它使用嵌套管道,在實踐中可能足夠快——而且它也可以改為使用foreach循環更新:現在確實如此,在第二個命令中)。

將 JSON 解析為哈希表( [hashtable] ,又名System.Collections.Hashtable )通過
-AsHashtable

  • 具有需要較少內存的優點ConvertFrom-Json默認輸出的[pscustomobject]實例的內部存儲有些低效)。

  • 具有不保留屬性輸入順序的潛在缺點,因為[hashtable]條目本質上是無序的; 然而,在手頭的情況下,這不是問題,因為創建了具有固定屬性順序的不同輸出對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM