【问题标题】:Powershell random shuffle/split large text filePowershell 随机洗牌/拆分大文本文件
【发布时间】:2015-05-21 17:59:04
【问题描述】:

Powershell 中是否有一种快速实现,可以使用 15%-85% 的拆分来随机打乱和拆分具有 1500 万行的文本文件?

很多资料都提到了如何使用 Get-Content,但 Get-Content 和 Get-Random 对于大文件来说速度很慢:

Get-Content "largeFile.txt" | Sort-Object{Get-Random}| Out-file "shuffled.txt"

我一直在寻找使用 Stream-Reader 和 Stream-Writer 的解决方案,但我不确定这是否可能。 Linux bash 似乎对我的 1500 万文件执行此操作非常快: How can I shuffle the lines of a text file on the Unix command line or in a shell script?

【问题讨论】:

    标签: powershell large-data


    【解决方案1】:

    不确定这是否会被充分随机化/随机化,但它应该会更快:

    $Idxs = 0..999
    Get-Content "largeFile.txt" -ReadCount 1000 | 
    foreach {
     $sample = Get-Random -InputObject $Idxs  -Count 150
     $_[$sample] |
     Add-Content 'shuffled.txt'
     }
    

    【讨论】:

    • 我认为这不够随机。这是在彼此之间洗牌每组 1000 行吗?我还尝试使用 -ReadCount 0 来拉入整个文件......但这让我记忆犹新。
    • 似乎总是抓住前 1000 个,然后在其中随机播放。也许 Idxs 可以是一组随机索引?
    【解决方案2】:

    我试图使用流读取器/写入器来避免占用内存,因为其中一些文件超过 300MB。我找不到完全避免内存的方法,但我没有将文件放入内存,而是创建了一个介于 0 和 Total Lines 之间的随机数字数组。该数组指示将哪些行放入示例文件中。

    为数据创建流阅读器

    $reader = New-Object -TypeName System.IO.StreamReader("data.txt");
    

    为测试群体创建流编写器

    $writer_stream = New-Object -TypeName System.IO.FileStream(
        ("test_population.txt"),
        [System.IO.FileMode]::Create,
        [System.IO.FileAccess]::Write);
    $writer= New-Object -TypeName System.IO.StreamWriter(
        $writer_stream,
        [System.Text.Encoding]::ASCII);
    

    为控制组创建 Stream Writer

    $writer_stream_control = New-Object -TypeName System.IO.FileStream(
        ("control.txt"),
        [System.IO.FileMode]::Create,
        [System.IO.FileAccess]::Write);
    $writer_control= New-Object -TypeName System.IO.StreamWriter(
        $writer_stream_control,
        [System.Text.Encoding]::ASCII);
    

    确定控件大小并随机选择介于 0 和文件总行数之间的数字。

    $line_count = 10000000
    $control_percent = 0.15
    $control_size = [math]::round($control_percent*$line_count)
    

    创建一个随机数索引以确定哪些行应该进入示例文件。确保在最后通过排序管道。

    $idx = Get-Random -count $control_size -InputObject(0..($line_count-1))|sort -Unique
    

    将 $i 表示为行号;使用 $idx[$j] 作为应该转到示例文件的行

    $i = 0; $j = 0
    while ($reader.Peek() -ge 0) {    
        $line = $reader.ReadLine() #Read Line
        if ($idx[$j] -eq $i){
            $writer_control.WriteLine($OutPut)
            $j++
            }
        else{$writer.WriteLine($OutPut)}
        }
        $i++
    
    $reader.Close();
    $reader.Dispose();
    
    $writer.Flush();
    $writer.Close();
    $writer.Dispose();
    
    $writer_control.Flush();
    $writer_control.Close();
    $writer_control.Dispose();
    

    【讨论】: