Get-Content -Wait блокирует файл во время его чтения, не позволяя Add-Content записывать данные

Я использую powershell для записи и чтения файлов журнала.

Один сценарий создает файл журнала с помощью Add-Content. Другой скрипт следит за файлом журнала, используя Get-Content -Wait. Кажется, это должно быть довольно надежно.

Однако писатель часто не может писать, а читатель часто не может читать и сдается. Я могу только предположить, что эти две команды не открывают файл с соответствующими флагами доступа, и поэтому они борются друг с другом.

Вот неприятный маленький скрипт, который демонстрирует проблему с двумя заданиями в одном процессе, хотя то же самое происходит между разными процессами powershell:

$writer = start-job -ScriptBlock {     
    foreach($i in 1..500)
    {
        "$i" | Add-Content "c:\temp\blah.txt"
        Sleep -Milliseconds 10
    }
}

$reader = start-job -ScriptBlock { 
    Get-Content "c:\temp\blah.txt" -wait
}

while($writer.State -eq "Running")
{
    Sleep 1
}
Sleep 2

"Checking writer"
receive-job $writer

"Checking reader"
receive-job $reader

remove-job $writer -force
remove-job $reader -force

На моем компьютере с Windows 7 x64 с Powershell 3 ISE я обычно получаю много ошибок записи:

Checking writer
The process cannot access the file 'C:\temp\blah.txt' because it is being used by another process.
    + CategoryInfo          : ReadError: (C:\temp\blah.txt:String) [Get-Content], IOException
    + FullyQualifiedErrorId : GetContentReaderIOError,Microsoft.PowerShell.Commands.GetContentCommand
    + PSComputerName        : localhost

И тогда в читаемом файле есть пробелы:

Checking reader
...
23
24
25
54
55
56
...

Обратите внимание, что это проблема, отличная от обсуждаемой здесь: Get-Content -wait не работает, как описано в документации и здесь: https://social.technet.microsoft.com/Forums/windowsserver/en-US/e8ed4036-d822-43d3-9ee5-dd03df3d9bfc/why-doesnt-wait-work-and-why-doesnt-one-sem-to-care?forum=winserverpowershell файл, который не закрывается между записями.

Есть ли способ использовать Get-Content и Add-Content, как это, или я должен отказаться и использовать что-то еще для чтения и записи файлов журнала?


person ben    schedule 09.06.2015    source источник


Ответы (1)


Попробуйте использовать Out-File вместо Add-Content

Заменять

Add-Content "c:\temp\blah.txt"

С участием:

Out-File "c:\temp\blah.txt" -Append -Encoding ascii

Вам нужно указать кодировку как ascii с Out-File, если это то, что вы хотите, поскольку это значение по умолчанию для добавления содержимого, но не значение по умолчанию для исходящего файла. Вам также необходимо использовать -append и/или -noclobber, чтобы избежать перезаписи существующего содержимого файла.

person campbell.rw    schedule 13.08.2015
comment
Обходным решением было бы сделать копию файла и прочитать его вместо этого, я подозреваю, что это может быть скорость, с которой он это делает, поэтому вы также можете включить начальный сон. - person Nick Eagle; 21.08.2015
comment
@Nick Создание копии файла связано с той же проблемой - оно может конфликтовать с Add-Content, что приводит к сбою записи. Этот подход также не имеет семантики -Wait, которая является причиной использования Get-Content. ср. хвост в баш. Сны — это не решение, они просто снижают вероятность возникновения проблемы, затрудняя ее обнаружение при тестировании, но не менее вредно в производственной среде. - person ben; 04.03.2016
comment
@campbell Out-File делает свое дело. Это похоже на ошибку (или, по крайней мере, на отсутствующую функцию) в Add-Content, ловушку, в которую могут попасть неосторожные сценаристы. Add-Content считается вредным? - person ben; 04.03.2016
comment
Это ошибка в Add-Content, которая была исправлена, но не в PowerShell 5.1. github.com/PowerShell/PowerShell/issues/5924 - person fjarlq; 16.11.2020