You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell处理220万条CSV转JSON耗时过长,求优化方案

PowerShell处理220万条CSV数据的性能优化方案

问题描述

我正在使用PowerShell读取一个包含220万条记录的CSV文件,仅需处理第一列的数值型数据,将其转换为IP地址后写入JSON文件,但该操作耗时近12小时,恳请提供代码优化方案或多线程实现思路。

示例CSV仅关注第一列,第一列内容为整数格式的IP地址(如3232235521对应192.168.0.1)。

现有代码

function Read-IPData
{
    $dbFilePath = Get-ChildItem -Path $rootDir -Filter "IP2*.CSV" | ForEach-Object{ $_.FullName }
    Write-Host "file path - $dbFilePath"

    Write-Host "Reading..."
    $data = Get-Content -Path $dbFilePath | Select-Object -Skip 1
    Write-Host "Reading data finished"

    $count = $data.Count
    Write-host "Total $count records found"

    return $data
}

function Convert-NumbetToIP
{
    param(
    [Parameter(Mandatory=$true)][string]$number
    )

    try
    {    
        $w = [int64]($number/16777216)%256
        $x = [int64]($number/65536)%256
        $y = [int64]($number/256)%256
        $z = [int64]$number%256

        $ipAddress = "$w.$x.$y.$z"
        Write-Host "IP Address - $ipAddress"

        return $ipAddress
    }
    catch
    {
        Write-Host "$_"
        continue
    }
}

Write-Host "Getting IP Addresses from $dbFileName"
$data = Read-IPData

Write-Host "Checking whether output.json file exist, if not create"
$outputFile = Join-Path -Path $rootDir -ChildPath "output.json"

if(!(Test-Path $outputFile))
{
    Write-Host "$outputFile does not exist, creating..."
    New-Item -Path $outputFile -type "file"
}

foreach($item in $data)
{
    $row = $item -split ","
    $ipNumber = $row[0].trim('"')

    Write-Host "Converting $ipNumber to ipaddress"
    $toIpAddress = Convert-NumbetToIP -number $ipNumber

    Write-Host "Preparing document JSON"
    $object = [PSCustomObject]@{
        "ip-address" = $toIpAddress
        "is-vpn" = "true"
        "@timestamp" = (Get-Date).ToString("o")
    }

    $document = $object | ConvertTo-Json -Compress -Depth 100
    Write-Host "Adding document - $document"
    Add-Content -Path $outputFile $document
}

性能瓶颈分析

现有代码的主要性能问题包括:

  • 全量加载数据:Get-Content一次性将220万行加载到内存,占用大量资源且加载速度慢
  • 逐行写入文件:Add-Content每次写入都要执行打开、写入、关闭文件操作,IO开销极大
  • 大量控制台输出:Write-Host的控制台输出是高耗时操作,220万次调用会严重拖慢整体速度
  • 低效的字符串处理:手动用-split ","分割CSV行,比专用CSV解析器效率低
  • 重复的JSON序列化:每次循环调用ConvertTo-Json,单条数据的序列化开销累积后非常可观
  • IP转换的计算冗余:手动计算IP段的方式可替换为更高效的原生.NET方法

优化方案

一、单线程优化(立竿见影,兼容PowerShell 5.1/7)

以下优化无需并行即可大幅降低耗时:

  1. 用Import-Csv高效读取指定列
    避免手动分割CSV,直接用Import-Csv加载仅需要的第一列,减少内存占用和解析开销。

  2. 批量写入文件
    先将所有JSON字符串收集到数组中,最后一次性写入文件,避免频繁IO操作。

  3. 移除冗余控制台输出
    完全移除所有Write-Host,或仅保留关键进度提示(如每10万条输出一次)。

  4. 优化IP转换逻辑
    使用.NET原生的[System.Net.IPAddress]类进行转换,比手动计算更高效可靠。

  5. 手动构造JSON字符串
    由于JSON结构固定,直接拼接字符串替代ConvertTo-Json,减少序列化开销。

单线程优化后代码

$rootDir = "你的CSV文件所在目录"
$outputFile = Join-Path -Path $rootDir -ChildPath "output.json"

# 获取CSV文件路径
$dbFilePath = (Get-ChildItem -Path $rootDir -Filter "IP2*.CSV").FullName
if (-not $dbFilePath) {
    Write-Error "未找到目标CSV文件"
    exit 1
}

# 定义高效IP转换函数
function Convert-NumberToIP {
    param([Parameter(Mandatory=$true)][int64]$number)
    try {
        $bytes = [System.BitConverter]::GetBytes($number)
        [array]::Reverse($bytes) # 转换为大端字节序
        return [System.Net.IPAddress]::new($bytes).ToString()
    }
    catch {
        # 异常处理,可记录错误到日志,此处跳过错误记录
        return $null
    }
}

# 初始化结果数组
$jsonLines = @()
$recordCount = 0
$timestamp = (Get-Date).ToString("o") # 若允许统一时间戳,用此;若需每条实时,移到循环内

# 逐行读取CSV(自动跳过表头)
Import-Csv -Path $dbFilePath -Header "IPNumber", "Ignore" | ForEach-Object {
    $recordCount++
    $ipNumber = [int64]$_.IPNumber
    $ipAddress = Convert-NumberToIP -number $ipNumber

    if ($ipAddress) {
        # 手动构造JSON字符串
        $jsonLine = @"
{"ip-address":"$ipAddress","is-vpn":"true","@timestamp":"$timestamp"}
"@
        $jsonLines += $jsonLine
    }

    # 可选:每10万条输出一次进度,避免控制台拖慢
    if ($recordCount % 100000 -eq 0) {
        Write-Host "已处理 $recordCount 条记录"
    }
}

# 一次性写入所有内容
Set-Content -Path $outputFile -Value $jsonLines -Encoding utf8

Write-Host "处理完成,共写入 $($jsonLines.Count) 条记录到 $outputFile"

二、并行处理优化(PowerShell 7+推荐,进一步提升速度)

如果使用PowerShell 7及以上版本,可利用ForEach-Object -Parallel实现并行处理,充分利用多核CPU。注意文件写入的线程安全,建议每个线程处理一块数据并写入临时文件,最后合并临时文件。

并行处理示例代码

$rootDir = "你的CSV文件所在目录"
$outputFile = Join-Path -Path $rootDir -ChildPath "output.json"
$tempDir = Join-Path -Path $rootDir -ChildPath "temp_parallel"
$batchSize = 50000 # 每批处理5万条记录

# 创建临时目录
if (-not (Test-Path $tempDir)) {
    New-Item -Path $tempDir -ItemType Directory | Out-Null
}

# 获取CSV文件路径
$dbFilePath = (Get-ChildItem -Path $rootDir -Filter "IP2*.CSV").FullName
if (-not $dbFilePath) {
    Write-Error "未找到目标CSV文件"
    exit 1
}

# 定义并行处理用的IP转换函数
$convertIpScriptBlock = {
    param([int64]$number)
    try {
        $bytes = [System.BitConverter]::GetBytes($number)
        [array]::Reverse($bytes)
        return [System.Net.IPAddress]::new($bytes).ToString()
    }
    catch {
        return $null
    }
}

# 读取所有数据并分块
$allData = Import-Csv -Path $dbFilePath -Header "IPNumber", "Ignore"
$batches = for ($i=0; $i -lt $allData.Count; $i+=$batchSize) {
    $allData[$i..($i+$batchSize-1)] | Where-Object { $_ }
}

# 并行处理每批数据
$batchIndex = 0
$batches | ForEach-Object -Parallel {
    $batch = $_
    $batchNum = $using:batchIndex++
    $tempFile = Join-Path -Path $using:tempDir -ChildPath "batch_$batchNum.json"
    $convertFunc = $using:convertIpScriptBlock
    $timestamp = (Get-Date).ToString("o")

    $jsonLines = @()
    foreach ($item in $batch) {
        $ipNumber = [int64]$item.IPNumber
        $ipAddress = & $convertFunc -number $ipNumber
        if ($ipAddress) {
            $jsonLines += @"
{"ip-address":"$ipAddress","is-vpn":"true","@timestamp":"$timestamp"}
"@
        }
    }

    Set-Content -Path $tempFile -Value $jsonLines -Encoding utf8
    Write-Host "批次 $batchNum 处理完成"
} -ThrottleLimit 8 # 按需设置并发数,建议等于CPU核心数

# 合并所有临时文件到最终输出
Get-ChildItem -Path $tempDir -Filter "batch_*.json" | Sort-Object Name | Get-Content | Set-Content -Path $outputFile -Encoding utf8

# 清理临时文件
Remove-Item -Path $tempDir -Recurse -Force

Write-Host "并行处理完成,结果已写入 $outputFile"

优化效果说明

  • 单线程优化后,耗时可降低至几十分钟甚至更短(取决于硬件)
  • 并行处理可进一步利用多核CPU,在8核机器上可将耗时压缩至十几分钟

内容的提问来源于stack exchange,提问作者Naveen Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 05:10:27