1

別のプロセスによって現在開かれているファイルを移動したくありません。move-item PowerShell コマンドを使用して、現在開いているファイルを移動したり、さらに悪いことにコピーしたりする方法はありますか?

現在、プロセス A の出力フォルダーからプロセス B の入力フォルダーにデータ ファイルを転送する必要がある 2 つのプロセスがある状況があります。プロセス A がファイルを書き込み、PowerShell スクリプトがそのファイルをプロセス B が読み取るフォルダーに移動するという考え方です。

同じファイルが 2 回転送され、どちらも部分的なファイルではないという問題が発生することがあります。

以下のコードは、正時 00、10、20、30、40、50 分後に実行されます。Sambaサーバー上のプロセス B は、正時 05、15、25、35、45、55 分後に実行され、プロセス B がファイルの処理を完了すると、PowerShell スクリプトがファイルを配置するフォルダーからファイルを移動します。一度に移動される 1 KB のファイルは最大で約 12 個までです。

プロセス A は私たちによって制御されておらず、いつでもその場所にファイルを書き込むことができます。PowerShell スクリプトがファイルを移動する直前にプロセス A がファイルを作成すると、競合状態が発生しているようです。スクリプトはファイルをコピーし、10 分後にスクリプトを再度実行すると移動します。

以下のコードでは、ログ ファイルに「Moved File」という同じファイルの 2 つのエントリが記録されている場合、プロセス A がファイルを 2 回作成している可能性はありますか?

$source = "C:\folder\*.txt"
$target_dir = "\\samba-server\share\"
$bad_dir = "C:\folder\bad_files\"
$log = "C:\SystemFiles\Logs\transfer.log"

$files = Get-ChildItem $source
foreach ($file in $files){

    if ($file.name -eq $null) {
        # Nothing to do, Added this in since for some reason it executes the conditions below
    }
    elseif (test-path ($target_dir + $file.name)) {

        # If there is a duplicate file, write to the log file, then copy it to the bad dir with
        # the datetime stamp in front of the file name

        $log_string = ((Get-Date -format G) + ",Duplicate File," + "'" + $file.name + "', " + $file.LastWriteTime)
        write-output ($log_string) >> $log
        $new_file = ($bad_dir + (get-date -format yyyy.MM.dd.HHmmss) + "_" + $file.name)
        move-item $file.fullname $new_file
    }
    else {
        # The file doesnt exist on the remote source, so we are good to move it.

        move-item $file.fullname $target_dir
        if ($?) { # If the last command completed successfully
            $log_string = ((Get-Date -format G) + ",Moved File," + "'" + $file.name + "', " + $file.LastWriteTime)
        } else {
            $log_string = ((Get-Date -format G) + ",Failed to Move File," + "'" + $file.name + "', " + $file.LastWriteTime)
        }
        write-output ($log_string) >> $log
    }
}
4

1 に答える 1

3

これは、よく研究されているトピックである古典的な生産者と消費者の問題です。

あなたが試すかもしれないいくつかの解決策は、ファイルの最終書き込み時間をチェックすることです。過去に十分な場合は、問題なく移動できます。もう 1 つは、排他アクセスでファイルを開こうとしている可能性があります。失敗した場合、ファイルはまだプロデューサー プロセスによって使用されています。それ以外の場合は、ファイルを閉じて移動します。

いくつかの例はそのようなものですが、

# List files that were modified at least five minutes ago
gci | ? { $_.lastwritetime -le (get-date).addminutes(-5) }

# Try to open a file with exclusive mode
try {

    $f1 = [IO.File]::Open("c:\temp\foo.txt", [IO.Filemode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::None)
    # If that didn't fail, close and move the file to new location
    $f1.Close()
    $f1.Dispose()
    Move-Item "c:\temp\foo.txt" $newLocation

} catch [System.IO.IOException]{
    "File is already open" # Catch the file is locked exception, try again later
}
于 2013-07-02T05:05:06.263 に答える