【问题标题】:Tell Powershell to wait for foreach to finish writing to txt file告诉 Powershell 等待 foreach 完成写入 txt 文件
【发布时间】:2020-08-31 10:05:42
【问题描述】:

我有一个 .ps1 脚本,它获取我们的一些内部 SQL 数据并将其同步到 Google API。

它通过针对我们的数据运行 foreach、使用逻辑生成 API 命令并通过 System.IO.StreamWriter 将这些命令写入文本文件来实现这一点。然后 API 处理器对文件运行批处理作业。

我遇到的问题是批处理作业部分似乎在 foreach 完成写入文件之前被触发,这使得整个脚本失败。

这是我的代码的简化版本:

$stream = [System.IO.StreamWriter] "C:\GAM\uploads\stream\gamBatch$today.txt";

## Loop csv and generate Google OU path
Write-Host "Generating location strings, OU paths, and update commands..."

Import-CSV "C:\uploads\Upload$today.csv" | ForEach-Object {

  ## Define fancy vars here
  ## Do fancy logic here

  ## Stream command list to log file
  $line = "update $deviceId assetid $Barcode location $location ou $ouPath";
  $stream.WriteLine($line);
};

## Trim top line of batch file (Removes header line)
(Get-Content "C:\uploads\stream\Batch$today.txt" | Select-Object -Skip 1) | Set-Content "C:\uploads\stream\Batch$today.txt";

## Close Stream instance and bulk run commands
Write-Host "Running batch command..."

$stream.WriteLine("commit-batch");
$stream.close();

apiBatch "C:\uploads\stream\Batch$today.txt";

这会在我的日志中生成此错误:

PS>TerminatingError(Set-Content): "The process cannot access the file 
'C:\uploads\stream\Batch2020-05-14.txt' because it is being used by another process."

如何让 Powershell 在触发批处理命令之前等待 txt 文件完成写入?

【问题讨论】:

  • 为什么不直接skip在第一行添加文件?
  • 它是一个 csv 文件,第一行是我没有包含的逻辑所需的标题。不是完全需要删除它,但更清洁

标签: powershell foreach batch-processing synchronous streamwriter


【解决方案1】:

无需将第一行写入文件,只需在之后立即再次将其删除(并且必须重写文件的其余部分)。

如果您在 ForEach-Object 循环中没有对它做任何有意义的事情,请立即跳过它:

Import-CSV "C:\uploads\Upload$today.csv" | Select-Object -Skip 1 | ForEach-Object {
    # ...
    $stream.WriteLine($line)
}

如果您需要检查 ForEach-Object 正文中的第一行,请确保在第一次迭代时跳过调用 WriteLine()

$first = $true
Import-CSV "C:\uploads\Upload$today.csv" | ForEach-Object {
    # ...
    if($first){
        $first = $false
    }
    else{
        $stream.WriteLine($line)
    }
}

或者,在使用Set-Content 重新写入文件之前关闭StreamWriter,然后使用Add-Content 或新的流写入器写入最后一行:

Import-CSV "C:\uploads\Upload$today.csv" | ForEach-Object {
    # ...
    $stream.WriteLine($line)
}

# dispose of the current writer (will close the file stream)
$stream.Dispose()

... | Set-Content "C:\uploads\stream\Batch$today.txt"

# open a new writer and append the last string
$stream = (Get-Item "C:\uploads\stream\Batch$today.txt").AppendText()
$stream.WriteLine("commit-batch")

# or use `Add-Content`
"commit-batch" | Add-Content "C:\uploads\stream\Batch$today.txt"

【讨论】:

  • 谢谢!我不知道 Set-Content 会重写文件。在这和 foreach 之前的 Skip-Object 参数之间,我想我有我需要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
相关资源
最近更新 更多