如何使用powershell重新排序CSV列

Ber*_*ken 12 csv powershell

输入文件:

column1;column2;column3
data1a;data2a;data3a
data1b;data2b;data3b
Run Code Online (Sandbox Code Playgroud)

目标:输出带有重新排序列的文件,比方说

column1;column3;column2
...
Run Code Online (Sandbox Code Playgroud)

更新问题:使用PowerShell解决此问题的好方法是什么.我知道存在与CSV相关的cmdlet,但这些都有局限性.请注意,不需要更改记录的顺序,因此不需要将整个输入/输出文件加载到内存中.

Rom*_*min 19

这是适用于数百万条记录的解决方案(假设您的数据没有嵌入';')

$reader = [System.IO.File]::OpenText('data1.csv')
$writer = New-Object System.IO.StreamWriter 'data2.csv'
for(;;) {
    $line = $reader.ReadLine()
    if ($null -eq $line) {
        break
    }
    $data = $line.Split(";")
    $writer.WriteLine('{0};{1};{2}', $data[0], $data[2], $data[1])
}
$reader.Close()
$writer.Close()
Run Code Online (Sandbox Code Playgroud)

  • 我同意这是这组数据的快速解决方案.但是,它可能无法处理字段分隔符出现在字段数据中的引用字段. (4认同)

EBG*_*een 15

Import-CSV C:\Path\To\Original.csv | Select-Object Column1, Column3, Column2 | Export-CSV C:\Path\To\Newfile.csv
Run Code Online (Sandbox Code Playgroud)

  • 幸运的是,“Import-CSV”在通过管道传输时不会将整个文件读入内存,并且此解决方案比我的 Powershell 版本更快(32 分 44 秒)。不过,“Export-CSV”可能需要被告知不要将每个字段都用引号引起来。:) (2认同)

Joe*_*ant 5

编辑:下面的基准测试信息.

我不会使用Powershell csv相关的cmdlet.我会用两种System.IO.StreamReaderMicrosoft.VisualBasic.FileIO.TextFieldParser对文件中的行由行,以避免加载在内存中的整个事情在读,我会用System.IO.StreamWriter它写回.该TextFieldParser内部使用StreamReader,但处理解析分隔的字段,这样你就不必了,使得它非常有用的,如果CSV格式并不简单(例如,在带引号的字段分隔符).

我根本不会在Powershell中这样做,而是在.NET应用程序中,因为即使它们使用相同的对象,它也会比Powershell脚本快得多.

这是一个简单版本的C#,假设没有引用字段和ASCII编码:

static void Main(){
    string source = @"D:\test.csv";
    string dest = @"D:\test2.csv";

    using ( var reader = new Microsoft.VisualBasic.FileIO.TextFieldParser( source, Encoding.ASCII ) ) {
        using ( var writer = new System.IO.StreamWriter( dest, false, Encoding.ASCII ) ) {
            reader.SetDelimiters( ";" );
            while ( !reader.EndOfData ) {
                var fields = reader.ReadFields();
                swap(fields, 1, 2);
                writer.WriteLine( string.Join( ";", fields ) );
            }
        }
    }
}

static void swap( string[] arr, int a, int b ) {
    string t = arr[ a ];
    arr[ a ] = arr[ b ];
    arr[ b ] = t;
}
Run Code Online (Sandbox Code Playgroud)

这是Powershell版本:

[void][reflection.assembly]::loadwithpartialname("Microsoft.VisualBasic")

$source = 'D:\test.csv'
$dest = 'D:\test2.csv'

$reader = new-object Microsoft.VisualBasic.FileIO.TextFieldParser $source
$writer = new-object System.IO.StreamWriter $dest

function swap($f,$a,$b){ $t = $f[$a]; $f[$a] = $f[$b]; $f[$b] = $t}

$reader.SetDelimiters(';')
while ( !$reader.EndOfData ) {
    $fields = $reader.ReadFields()
    swap $fields 1 2
    $writer.WriteLine([string]::join(';', $fields))
}

$reader.close()
$writer.close()
Run Code Online (Sandbox Code Playgroud)

我将这两个基准与一个包含10,000,000行的3列csv文件进行了对比.C#版本花了171.132秒(不到3分钟).Powershell版本耗时2,364.995秒(39分25秒).

编辑:为什么我的这么长时间.

交换功能是我的Powershell版本中的一个巨大瓶颈.用'{0};{1};{2}'罗曼库兹明的答案替换为式式输出将其缩短到不到9分钟.更换TextFieldParser一半以上在4分钟内剩余.

但是,一个.NET控制台应用程序版本的Roman Kuzmin的答案花了20秒.


ste*_*tej 5

很高兴人们带来了基于纯.NET的解决方案.但是,如果可能的话,我会为简单而战.这就是为什么我向你们所有人投票;)

为什么?我尝试生成1.000.000记录并将其存储在CSV中,然后重新排序列.在我的情况下生成csv比重新排序要求更高.看看结果.

只需1.8分钟就可以对列进行重新排序.对我而言,这是相当不错的结果.对我好吗?- >是的,我不需要尝试找出更快的解决方案,这已经足够了 - >为其他一些有趣的东西节省了我的时间 ;)

# generate some csv; objects have several properties
measure-command { 
    1..1mb | 
    % { 
        $date = get-date
        New-Object PsObject -Property @{
            Column1=$date
            Column2=$_
            Column3=$date.Ticks/$_ 
            Hour = $date.Hour
            Minute = $date.Minute
            Second = $date.Second
            ReadableTime = $date.ToLongTimeString()
            ReadableDate = $date.ToLongDateString()
        }} | 
    Export-Csv d:\temp\exported.csv 
}

TotalMinutes      : 6,100025295

# reorder the columns
measure-command { 
    Import-Csv d:\temp\exported.csv | 
        Select ReadableTime, ReadableDate, Hour, Minute, Second, Column1, Column2, Column3 | 
        Export-Csv d:\temp\exported2.csv 
}

TotalMinutes      : 2,33151559833333
Run Code Online (Sandbox Code Playgroud)