2

我有一个包含以下内容的大型文本文件 World.net(这是一个 Pajek 文件,但将其视为文本):

*Vertices 999999
    1 ""                                       0.2931    0.2107    0.5000 empty
    2 ""                                       0.2975    0.2214    0.5000
    3 ""                                       0.3083    0.2258    0.5000
    4 ""                                       0.3127    0.2406    0.5000
    5 ""                                       0.3083    0.2514    0.5000
    6 ""                                       0.3147    0.2578    0.5000
...
    999999 ""                                       0.3103    0.2622    0.5000
*Edges :2 "World contours"
    1     2 1 
    2     3 1 
    3     4 1 
    4     5 1 
    5     6 1 
    6     7 1 
...
    983725     8 1 

我想将它拆分为不同的 .txt 文件,以开头的行

*[某物]

[Something] 应该进入像 World_Vertices.txt 和 World_Edges.txt 这样的文件名。

文件内容应该是原始文件中每个类别(顶点、边)之后的行 (1,2,3...),没有类别名称(以 * 开头)。

我有一个(有点)有效的代码:

$filename = "World"
echo $pwd\"$filename.net"
$file = New-Object System.IO.StreamReader -Arg "$pwd\$filename.net"
while (($line = $file.ReadLine()) -ne $null) {
    If ($line -match "^\*\w+") {
        $newfile = -join("$filename ","$($line.Split('\*')[1]).txt")
        echo $newfile
    }
    Else {
        $line | Out-File -Append $newfile
    }
}

但是这段代码很慢。一个 10 mb 的文件需要 20 分钟。我希望能够处理一个 4GB 的文件。

硬件说明: 机器不错:i7 带混合磁盘,16GB 内存,我可以安装 .net 框架,无论哪种工作都需要。

编辑 1:最终代码 修复了已接受答案中的一些错误,这是我使用的最终代码(它可能对任何想要编辑大型 pajek 文件的人都有帮助):

$filename = "World.net"
$file = New-Object System.IO.StreamReader -Arg "$pwd\$filename"
$writer = $null
$n = 0
while (($line = $file.ReadLine()) -ne $null) {
    If ($line.StartsWith("*")) {
        $n = 1
        $newfile = -join("$filename ","$($line.Split('\*')[1]).txt")
        echo $newfile
        if ($null -ne $writer) {
            $writer.Dispose()
        }
        $writer = New-Object System.IO.StreamWriter "$pwd\$newfile"
    }
    Else {
        If ($n -eq 0){
            $writer.WriteLine()
        }
        $writer.Write($line)
        $n = 0
    }
}
 $writer.Dispose()
4

2 回答 2

2

通常,当性能很重要时,在 PowerShell 中使用 .NET 函数始终是最好的方法。所以使用 aStreamReader已经是一个很好的方法。

我将您的代码更改为使用 aStreamWriter写入输出文件:

$filename = "World"
echo "$pwd\$filename.net"
$file = New-Object System.IO.StreamReader -Arg "$pwd\$filename.net"
$writer = $null
while (($line = $file.ReadLine()) -ne $null) {
    If ($line -match "^\*\w+") {
        $newfile = -join("$filename ","$($line.Split('\*')[1]).txt")
        echo $newfile
        if ($null -ne $writer) {
            $writer.Dispose()
        }
        $writer = New-Object System.IO.StreamWriter "$pwd\$newfile"
    }
    Else {
        $writer.WriteLine($line)
    }
}

尝试一下。

还有其他方法可以进一步提高您的表现。例如,您可能会跳过昂贵的正则表达式检查。改用这个:

if ($line.StartsWith("*"))
于 2017-09-19T07:09:43.643 回答
1

一般来说,写作需要很多开销。
因此,将部分数据保存在内存中,直到完成,然后一次写入整个部分:

$filename = "World"
echo $pwd\"$filename.net"
$file = New-Object System.IO.StreamReader -Arg "$pwd\$filename.net"
while (($line = $file.ReadLine()) -ne $null) {
    If ($line -match "^\*\w+") {
        If ($newfile) {$section | Out-File $newfile}
        $newfile = -join("$filename ","$($line.Split('\*')[1]).txt")
        echo $newfile
        $section = @()
    }
    Else {
        $Section += $line
    }
}
If ($newfile) {$section | Out-File $newfile}
于 2017-09-19T08:33:14.763 回答