3

大きな CSV ファイル (それぞれ 50 ~ 500 MB) があります。これらで複雑なパワーシェルコマンドを実行すると、時間がかかり、メモリの問題が発生します。

データを処理するには、ColumnA などの共通フィールドでグループ化する必要があります。したがって、データがすでにその列でソートされていると仮定すると、これらのファイルをランダムに (つまり、x 千行ごとに) 分割すると、一致するエントリが別の部分になる可能性があります。A には何千もの異なるグループがあるため、すべてを 1 つのファイルに分割すると、多くのファイルが作成されます。

グループを失わずに、10,000行程度のファイルに分割するにはどうすればよいですか? たとえば、行 1 ~ 13 は列 A の A1 になり、行 14 ~ 17 は A2 になり、行 9997 ~ 10012 は A784 になります。この場合、最初のファイルに行 1 ~ 10012 を含め、次のファイルを行 10013 から開始する必要があります。

明らかに、(列 A だけではなく) 行全体を保持したいので、結果のファイルをすべて貼り付けると、元のファイルと同じになります。

4

3 に答える 3

5

未検証。これは、ColumnA が最初の列であり、共通のコンマ区切りデータであると想定しています。データに合わせて正規表現を作成する行を調整する必要があります。

 $count = 0

 $header = get-content file.csv -TotalCount 1

 get-content file.csv -ReadCount 1000 |
  foreach {
   #add tail entries from last batch to beginning of this batch
   $newbatch = $tail + $_ 

   #create regex to match last entry in this batch
   $regex = '^' + [regex]::Escape(($newbatch[-1].split(',')[0])) 

   #Extract everything that doesn't match the last entry to new file

     #Add header if this is not the first file
     if ($count)
       {
         $header |
           set-content "c:\somedir\filepart_$count"
        }

     $newbatch -notmatch $regex | 
      add-content "c:\somedir\filepart_$count"  

   #Extact tail entries to add to next batch
   $tail = @($newbatch -match $regex)

   #Increment file counter
   $count++ 

}
于 2013-02-07T15:32:49.300 に答える
2

これは私の試みです、それは乱雑になりました:-P 分割しながらファイル全体をメモリにロードしますが、これは純粋なテキストです。インポートされたオブジェクトよりも少ないメモリを使用する必要がありますが、それでもファイルのサイズについてです。

$filepath = "C:\Users\graimer\Desktop\file.csv"
$file = Get-Item $filepath
$content = Get-Content $file
$csvheader = $content[0]
$lines = $content.Count
$minlines = 10000
$filepart = 1

$start = 1

while ($start -lt $lines - 1) {
    #Set minimum $end value (last line)
    if ($start + $minlines -le $lines - 1) { $end = $start + $minlines - 1 } else { $end = $lines - 1 }

    #Value to compare. ColA is first column in my file = [0] .  ColB is second column = [1]
    $avalue = $content[$end].split(",")[0]
    #If not last line in script
    if ($end -ne $lines -1) {
        #Increase $end by 1 while ColA is the same
        while ($content[$end].split(",")[0] -eq $avalue) { $end++ }
        #Return to last line with equal ColA value
        $end--
    }
    #Create new csv-part
    $filename = $file.FullName.Replace($file.BaseName, ($file.BaseName + ".part$filepart"))
    @($csvheader, $content[$start..$end]) | Set-Content $filename

    #Fix counters
    $filepart++
    $start = $end + 1
}

ファイル.csv:

ColA,ColB,ColC
A1,1,10
A1,2,20
A1,3,30
A2,1,10
A2,2,20
A3,1,10
A4,1,10
A4,2,20
A4,3,30
A4,4,40
A4,5,50
A4,6,60
A5,1,10
A6,1,10
A7,1,10

結果(私が使用し$minlines = 5た):

file.part1.csv:

ColA,ColB,ColC
A1,1,10
A1,2,20
A1,3,30
A2,1,10
A2,2,20

file.part2.csv:

ColA,ColB,ColC
A3,1,10
A4,1,10
A4,2,20
A4,3,30
A4,4,40
A4,5,50
A4,6,60

file.part3.csv:

ColA,ColB,ColC
A5,1,10
A6,1,10
A7,1,10
于 2013-02-07T15:52:49.650 に答える
0

これには、PowerShell v3が必要です(-appendonのためExport-CSV)。

また、列ヘッダーがあり、最初の列の名前がであると想定していますcol1。必要に応じて調整してください。

import-csv MYFILE.csv|foreach-object{$_|export-csv -notypeinfo -noclobber -append ($_.col1 + ".csv")}

これにより、最初の列の個別の値ごとに1つのファイルが作成され、その値がファイル名になります。

于 2013-02-07T15:30:14.720 に答える