ファイルが使用中かどうかを確認する方法はありますか?


846

1つの画像ファイルに繰り返しアクセスする必要があるC#のプログラムを書いています。ほとんどの場合は機能しますが、コンピューターが高速で動作している場合は、ファイルシステムに保存される前にファイルにアクセスしようとし、「ファイルは別のプロセスで使用されています」というエラーをスローします。

これを回避する方法を見つけたいのですが、すべてのグーグルで例外処理を使用してチェックを作成することしかできませんでした。これは私の宗教に反するので、誰かがもっと良いやり方をしているのではないかと思っていました。


30
よし、システムで開いているすべてのハンドルを調べることでテストできます。ただし、Windowsはマルチタスクオペレーティングシステムであるため、コードを実行してファイルが開いているかどうかを判断し、開いていないと判断した直後に、プロセスコードがそのファイルの使用を開始し、その後、それを使用すると、エラーが発生します。しかし、最初にチェックすることに問題はありません。実際に必要なときに使用されていないと想定しないでください。
BobbyShaftoe、2009年

3
しかし、この特定の問題についてだけです。ファイルハンドルを調べずに、事前に設定された回数、たとえば3〜5回失敗するまで試すことをお勧めします。
BobbyShaftoe、2009年

この画像ファイルはどのように生成されますか?生成が完了するまでプログラムを停止/スリープ/一時停止できますか?これは、状況を処理するためのはるかに優れた方法です。そうでない場合は、例外処理の使用を回避できないと思います。
キャッチワ2009年

例外の使用はすべて、意図的に失敗の可能性を排除せずに、潜在的に危険なことを行うことによる何らかの仮定のチェックではありませんか?
jwg 2013年

26
あなたの哲学は例外をよく理解していません。ほとんどの人は、例外は神聖なくだらないアウトオブドゥーム何かの間違ったダイダイダイを意味すると考えています。例外が意味するとき...例外。これは、「処理」(または説明)が必要な例外が発生したことを意味します。データアクセスの再試行を継続したい場合もあれば、ユーザーが接続を取得できないことを知っている必要がある場合もあります。職業はなんですか?ConnectionFailedExceptionを処理してユーザーに通知すると、1時間後にユーザーが試行を停止し、ケーブルが外れていることに気付くでしょう。
Lee Louviere 2013年

回答:


543

このソリューションに関する更新された注記FileAccess.ReadWrite読み取り専用ファイルのチェックは失敗するため、ソリューションはでチェックするように変更されましたFileAccess.Read。このソリューションFileAccess.Readは、ファイルに書き込みロックまたは読み取りロックが設定されている場合にチェックしようとすると失敗するため機能しますが、ファイルに書き込みロックまたは読み取りロックが設定されていない場合、つまり、ファイルが開かれている場合は機能しません(読み取りまたは書き込み用)FileShare.ReadまたはFileShare.Writeアクセス。

オリジナル: このコードを過去数年間使用しており、問題は発生していません。

例外の使用についてためらいを理解しますが、例外を常に回避することはできません。

protected virtual bool IsFileLocked(FileInfo file)
{
    try
    {
        using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
        {
            stream.Close();
        }
    }
    catch (IOException)
    {
        //the file is unavailable because it is:
        //still being written to
        //or being processed by another thread
        //or does not exist (has already been processed)
        return true;
    }

    //file is not locked
    return false;
}

60
これは素晴らしい解決策ですが、コメントが1つあります。ファイルが読み取り専用の場合、ReadWriteは常に失敗するため、アクセスモードFileAccess.Readでファイルを開くことはできません。
adeel825 2010年

220
-1。IsFileLockedでファイルが閉じられた後、スレッドがファイルを開く機会が得られる前に、ファイルが別のスレッド/プロセスによってロックされる可能性があるため、これは適切な回答ではありません。
10

16
これは素晴らしい答えだと思います。私はこれを拡張メソッド ála として使用していpublic static bool IsLocked(this FileInfo file) {/*...*/}ます。
Manuzor

54
@ChrisW:何が起こっているのか疑問に思われるかもしれません。心配しないでください。あなただけの毎日WTFコミュニティの怒りを受けることだ:thedailywtf.com/Comments/...
ピエールLebeaupin

16
@ChrisWなぜそれが悪いのですか。このコミュニティは、良い答えと悪い答えを指摘するためにここにあります。多くの専門家がこれが悪いことだと気づき、反対投票に参加した場合、そのサイトはWAIです。そして否定的になる前に、あなたがその記事を読んだ場合、彼らは間違った答えに反対するのではなく、「正しい答えに賛成する」と言います。コメントで賛成投票も説明してほしいですか。別の良いサイトを紹介してくれてありがとう!
Lee Louviere、2013年

569

これに関するセキュリティ上の脆弱性として使用されている例のドキュメントがあるスレッド競合状態に悩まされる可能性があります。ファイルが利用可能であることを確認した後、それを試して使用すると、その時点でスローされる可能性があり、悪意のあるユーザーがコードを強制して悪用する可能性があります。

あなたの最善の策はtry catch /最終的にファイルハンドルを取得しようとすることです。

try
{
   using (Stream stream = new FileStream("MyFilename.txt", FileMode.Open))
   {
        // File/Stream manipulating code here
   }
} catch {
  //check here why it failed and ask user to retry if the file is in use.
}

124
+1。チェックを行ってから数ミリ秒後にファイルが使用されなくなったり、その逆の場合があるため、「ファイルが使用されているかどうかを知る」100%安全な方法はありません。代わりに、ファイルを開いて、例外がない場合はそれを使用します。
セダットカパノグル2011年

8
.NETはCASをサポートしていません。成功/失敗を返すTryOpenFile(Ref FileHandle)のようなもの。例外処理のみに依存しない回避策が常に必要です。Microsoft Officeがそれをどのように行うのかと思います。
TamusJRoyce 2011

2
ここで理解しておくべき重要なことは、このAPIが単にWindows APIを使用してファイルハンドルを取得していることです。そのため、C APIから受け取ったエラーコードを変換し、例外にラップしてスローする必要があります。.Netには例外処理があるので、使用しないでください。そうすることで、コードにクリーンなフォワードパスを記述し、エラー処理を別のコードパスに残すことができます。
スペンス

36
usingステートメントは、終了後にストリームを確実に閉じるためのものです。using(){}は、最終的に{obj.Dispose()}を試してみるよりも文字数が少ないことがわかると思います。また、usingステートメントの外でオブジェクト参照を宣言する必要があることもわかります。明示的なインターフェイスがある場合は、キャストする必要もあります。最後に、できるだけ早く破棄する必要があります。finallyロジックには、IDisposeの呼び出しとはほとんど関係のないUIまたは他の長時間実行アクションが含まれる場合があります。</ rant>
スペンス

2
これは、tryの外部でオブジェクトを宣言し、disposeを明示的に呼び出さなければならないという事実を否定するものではありません。これを使用すると、同じことを意味します。
Spence 2013年

92

これを使用して、ファイルがロックされているかどうかを確認します。

using System.IO;
using System.Runtime.InteropServices;
internal static class Helper
{
const int ERROR_SHARING_VIOLATION = 32;
const int ERROR_LOCK_VIOLATION = 33;

private static bool IsFileLocked(Exception exception)
{
    int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
    return errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION;
}

internal static bool CanReadFile(string filePath)
{
    //Try-Catch so we dont crash the program and can check the exception
    try {
        //The "using" is important because FileStream implements IDisposable and
        //"using" will avoid a heap exhaustion situation when too many handles  
        //are left undisposed.
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) {
            if (fileStream != null) fileStream.Close();  //This line is me being overly cautious, fileStream will never be null unless an exception occurs... and I know the "using" does it but its helpful to be explicit - especially when we encounter errors - at least for me anyway!
        }
    }
    catch (IOException ex) {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex)) {
            // do something, eg File.Copy or present the user with a MsgBox - I do not recommend Killing the process that is locking the file
            return false;
        }
    }
    finally
    { }
    return true;
}
}

パフォーマンス上の理由から、同じ操作でファイルの内容を読み取ることをお勧めします。ここではいくつかの例を示します。

public static byte[] ReadFileBytes(string filePath)
{
    byte[] buffer = null;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
                sum += count;  // sum is a buffer offset for next reading

            fileStream.Close(); //This is not needed, just me being paranoid and explicitly releasing resources ASAP
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
    }
    return buffer;
}

public static string ReadFileTextWithEncoding(string filePath)
{
    string fileContents = string.Empty;
    byte[] buffer;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
            {
                sum += count;  // sum is a buffer offset for next reading
            }

            fileStream.Close(); //Again - this is not needed, just me being paranoid and explicitly releasing resources ASAP

            //Depending on the encoding you wish to use - I'll leave that up to you
            fileContents = System.Text.Encoding.Default.GetString(buffer);
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    { }     
    return fileContents;
}

public static string ReadFileTextNoEncoding(string filePath)
{
    string fileContents = string.Empty;
    byte[] buffer;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0) 
            {
                sum += count;  // sum is a buffer offset for next reading
            }

            fileStream.Close(); //Again - this is not needed, just me being paranoid and explicitly releasing resources ASAP

            char[] chars = new char[buffer.Length / sizeof(char) + 1];
            System.Buffer.BlockCopy(buffer, 0, chars, 0, buffer.Length);
            fileContents = new string(chars);
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
    }

    return fileContents;
}

自分で試してください:

byte[] output1 = Helper.ReadFileBytes(@"c:\temp\test.txt");
string output2 = Helper.ReadFileTextWithEncoding(@"c:\temp\test.txt");
string output3 = Helper.ReadFileTextNoEncoding(@"c:\temp\test.txt");

8
そこに非常に多くの「マジックナンバー」がなかった場合、私はupvoteだろう)en.wikipedia.org/wiki/Magic_number_(programming
クリスは

3
私は、ビットシフトではなく、errorCode比較を参照していました。しかし、今あなたはそれについて言及します...
クリス

1
キャッチはIOException、一般ではなくでオンにExceptionしてから、型のテストをオンにする必要があります。
Askolein 2013

3
@JeremyThompson悲しいことにIOException、一般的なものの後に特定のものを置きます。一般的なものは通り過ぎるすべてのものをキャッチし、特定のものIOExceptionは常に孤独になります。2つを入れ替えるだけです。
Askolein 2013年

私はこのソリューションが好きです。他の1つの提案:if(IsFileLocked(ex))のelseとしてキャッチ内で、exをスローします。これにより、例外がスローされ、ファイルが存在しない場合(またはその他のIOExceptionの場合)が処理されます。
shindigo 2014

7

意図したとおりに例外を使用してください。ファイルが使用中であることを受け入れ、アクションが完了するまで繰り返し、再試行します。行動する前に状態をチェックするサイクルを無駄にしないため、これも最も効率的です。

たとえば、以下の関数を使用します

TimeoutFileAction(() => { System.IO.File.etc...; return null; } );

2秒後にタイムアウトする再利用可能なメソッド

private T TimeoutFileAction<T>(Func<T> func)
{
    var started = DateTime.UtcNow;
    while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
    {
        try
        {
            return func();                    
        }
        catch (System.IO.IOException exception)
        {
            //ignore, or log somewhere if you want to
        }
    }
    return default(T);
}

6

おそらく、FileSystemWatcherを使用して、Changedイベントを監視できます。

私はこれを自分で使用したことはありませんが、試してみる価値があるかもしれません。この場合、filesystemwatcherが少し重い場合は、try / catch / sleepループを使用します。


1
CreatedイベントとChangedイベントはファイルの作成/変更の開始時に発生するため、FileSystemWatcherを使用しても効果はありません。小さなファイルであっても、.NETアプリケーションがFileSystemEventHandlerコールバックを介して実行する必要があるよりも、オペレーティングシステムによって書き込まれたり閉じられたりするのに多くの時間が必要です。これはとても悲しいことですが、ファイルにアクセスするか、例外ループに

ただし、FileSystemWatcherは同時に多くの変更を適切に処理しないため、注意してください。
ベンF

1
ところで、MSが独自のFSW "FileSystemWather"を呼び出すスレッドをデバッグおよび監視しているときに気付いたことがありますか?とにかく天候は何ですか?
devlord 2013

FileSystemWatcherを使用するWindowsサービスが、プロセスがファイルを閉じる前にファイルを読み取ろうとしたため、この問題が発生しました。
freedeveloper

6

ストリームが利用可能になり次第、ストリームを提供するタスクを返すことができます。これは単純化されたソリューションですが、良い出発点です。スレッドセーフです。

private async Task<Stream> GetStreamAsync()
{
    try
    {
        return new FileStream("sample.mp3", FileMode.Open, FileAccess.Write);
    }
    catch (IOException)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        return await GetStreamAsync();
    }
}

このストリームは通常どおり使用できます。

using (var stream = await FileStreamGetter.GetStreamAsync())
{
    Console.WriteLine(stream.Length);
}

3
スタックが再帰からオーバーフローするまで何秒かかりGetStreamAsync()ますか?
CADブロークが2017

@CADbloke、あなたは非常に良い点を挙げました。実際、ファイルが長期間利用できない場合に備えて、私のサンプルにはスタックオーバーフロー例外があるかもしれません。この回答stackoverflow.com/questions/4513438/…に関連して、5時間で例外が発生する可能性があります。
Ivan Branets 2017

ユースケースに関連して、たとえば、ファイルの読み取りが10回失敗した場合は、I / O例外をスローすることをお勧めします。もう1つの戦略は、10回の試行が失敗した場合に1秒の待機時間を増やすことです。両方を組み合わせて使用​​することもできます。
Ivan Branets 2017

ファイルがロックされていることをユーザーに警告するだけです。彼らは一般的にそれを彼ら自身でロックしたので、彼らはおそらくそれについて何かをするでしょう。か否か。
CADが17

ファイルの準備がまだ整っていない場合があるため、場合によっては、再試行ポリシーを使用する必要があります。一時フォルダに画像をダウンロードするデスクトップアプリケーションを想像してみてください。アプリケーションがダウンロードを開始すると同時に、ファイルエクスプローラーでこのフォルダーを開きます。Windowsはすぐにサムネイルを作成してファイルをロックしたいと考えています。同時に、アプリはロックされた画像を別の場所に置き換えようとします。再試行ポリシーを使用しないと、例外が発生します。
Ivan Branets 2017

4

私が知っている唯一の方法は、あまり速くないWin32排他ロックAPIを使用することですが、例は存在しています。

ほとんどの人は、これの簡単な解決策として、ループを試す/キャッチ/スリープするだけです。


1
最初にファイルを開かないと、このAPIを使用できません。その時点で、ファイルを開く必要はありません。
ハリージョンストン

1
シュレディンガーのファイル。
TheLastGIS

4
static bool FileInUse(string path)
    {
        try
        {
            using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
            {
                fs.CanWrite
            }
            return false;
        }
        catch (IOException ex)
        {
            return true;
        }
    }

string filePath = "C:\\Documents And Settings\\yourfilename";
bool isFileInUse;

isFileInUse = FileInUse(filePath);

// Then you can do some checking
if (isFileInUse)
   Console.WriteLine("File is in use");
else
   Console.WriteLine("File is not in use");

お役に立てれば!


10
実際に行うチェックは問題ありません。関数内に置くと誤解を招きます。ファイルを開く前に、このような関数を使用したくありません。関数内では、ファイルが開かれ、チェックされ、閉じられます。次に、プログラマーはファイルがまだ使用できると想定し、使用するために開こうとします。これは、このファイルを開くためにキューに入れられた別のプロセスによって使用およびロックされる可能性があるため、不正です。最初に開かれたとき(チェック用)と2回目に開かれたとき(使用用)の間、OSがプロセスのスケジュールを解除し、別のプロセスを実行している可能性があります。
レイキー

3

上記の受け入れられた回答には、FileShare.Readモードで書き込み用にファイルが開かれている場合、またはファイルに読み取り専用属性がある場合、コードが機能しないという問題があります。この修正されたソリューションは最も信頼性の高い方法で動作し、2つの点に注意する必要があります(承認されたソリューションについても同様)。

  1. 書き込み共有モードで開かれたファイルには機能しません
  2. これはスレッドの問題を考慮していないため、ロックするか、スレッドの問題を個別に処理する必要があります。

上記を念頭に置いて、これはファイルが書き込み用にロックされている、読み取りを防ぐためにロックされているかを確認します。

public static bool FileLocked(string FileName)
{
    FileStream fs = null;

    try
    {
        // NOTE: This doesn't handle situations where file is opened for writing by another process but put into write shared mode, it will not throw an exception and won't show it as write locked
        fs = File.Open(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // If we can't open file for reading and writing then it's locked by another process for writing
    }
    catch (UnauthorizedAccessException) // https://msdn.microsoft.com/en-us/library/y973b725(v=vs.110).aspx
    {
        // This is because the file is Read-Only and we tried to open in ReadWrite mode, now try to open in Read only mode
        try
        {
            fs = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None);
        }
        catch (Exception)
        {
            return true; // This file has been locked, we can't even open it to read
        }
    }
    catch (Exception)
    {
        return true; // This file has been locked
    }
    finally
    {
        if (fs != null)
            fs.Close();
    }
    return false;
}

それでも、受け入れられた回答と同じ問題があります-ファイルが特定の時点で別のプロセスによってロックされたかどうかを通知するだけであり、これは有用な情報ではありません。関数が戻った時点で、結果はすでに古くなっている可能性があります。
Harry Johnston、

1
確かに、特定の時点でしか確認できない(またはイベントをサブスクライブする)ことができます。このアプローチが受け入れられたソリューションより優れている点は、読み取り専用属性と書き込みロックを確認でき、誤検知を返さないことです。
rboy

3

参考までに、3ライナーの使用を除いて:完全な情報が必要場合-Microsoft Dev Centerに小さなプロジェクトがあります。

https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4

はじめに:

.NET Framework 4.0で開発されたC#サンプルコードは、ファイルをロックしているプロセスを特定するのに役立ちます。 rstrtmgr.dllに含まれているRmStartSession関数は、再起動マネージャーセッションの作成に使用され、返された結果に従って、Win32Exceptionオブジェクトの新しいインスタンスが作成されます。RmRegisterRescources関数を介してリソースを再起動マネージャーセッションに登録した後 、RM_PROCESS_INFO配列を列挙して、RmGetList関数を呼び出し、アプリケーションが特定のファイルを使用しているものを確認します。

「Restart Manager Session」に接続することで機能します。

再起動マネージャーは、セッションに登録されているリソースのリストを使用して、シャットダウンして再起動する必要のあるアプリケーションとサービスを決定します。 リソースは、ファイル名、サービスの短い名前、または実行中のアプリケーションを説明するRM_UNIQUE_PROCESS構造によって識別できます。

それはあなたの特定のニーズに対して少しオーバーエンジニアリングされているかもしれません...しかし、それがあなたが望むものであるなら、先に進んでvs-projectを入手してください。


2

私の経験では、通常、これを実行し、ファイルを「保護」して奇妙なことを行い、「保護」されたファイルを使用します。このように使用したいファイルが1つしかない場合は、Jeremy Thompsonの回答で説明されているトリックを使用できます。ただし、これを多数のファイルで実行しようとすると(たとえば、インストーラーを作成しているときなど)、かなりの損害を被ります。

これを解決できる非常に洗練された方法は、ファイルシステムでフォルダー名の1つが使用されている場合、フォルダー名を変更できないという事実を利用することです。フォルダーを同じファイルシステムに保存しておけば、魅力的に機能します。

これが悪用される可能性がある明白な方法に注意する必要があることに注意してください。結局のところ、ファイルはロックされません。また、Move操作が失敗する可能性のある他の理由があることにも注意してください。明らかに適切なエラー処理(MSDN)がここで役立ちます。

var originalFolder = @"c:\myHugeCollectionOfFiles"; // your folder name here
var someFolder = Path.Combine(originalFolder, "..", Guid.NewGuid().ToString("N"));

try
{
    Directory.Move(originalFolder, someFolder);

    // Use files
}
catch // TODO: proper exception handling
{
    // Inform user, take action
}
finally
{
    Directory.Move(someFolder, originalFolder);
}

個々のファイルについては、Jeremy Thompsonが投稿したロックの提案を使用します。


こんにちは。回答の順序が変わるため、この人気のあるQAの読者にとって、上記のどの投稿を意味するかを明確にできます。ありがとう。
Jeremy Thompson、

1
@JeremyThompsonそうですね、ありがとう、私は投稿を編集します。主に正しい使い方FileShareとロックの確認のため、私はあなたからの解決策を使用します。
atlaste 2014年

2

以下に、私が知る限り、受け入れられた回答と同じことを行うコードをいくつか示します。

    public static bool IsFileLocked(string file)
    {
        try
        {
            using (var stream = File.OpenRead(file))
                return false;
        }
        catch (IOException)
        {
            return true;
        }        
    }

ただし、次の方法で行う方がより堅牢だと思います。

    public static void TryToDoWithFileStream(string file, Action<FileStream> action, 
        int count, int msecTimeOut)
    {
        FileStream stream = null;
        for (var i = 0; i < count; ++i)
        {
            try
            {
                stream = File.OpenRead(file);
                break;
            }
            catch (IOException)
            {
                Thread.Sleep(msecTimeOut);
            }
        }
        action(stream);
    }

2

私のライブラリを使用して、複数のアプリからファイルにアクセスできます。

nugetからインストールできます:Install-Package Xabe.FileLock

詳細については、https://github.com/tomaszzmuda/Xabe.FileLockを確認して ください。

ILock fileLock = new FileLock(file);
if(fileLock.Acquire(TimeSpan.FromSeconds(15), true))
{
    using(fileLock)
    {
        // file operations here
    }
}

fileLock.Acquireメソッドは、このオブジェクト専用のファイルをロックできる場合にのみtrueを返します。ただし、ファイルをアップロードするアプリもファイルロックで行う必要があります。オブジェクトにアクセスできない場合、メソッドはfalseを返します。


1
回答としてツールやライブラリを投稿しないでください。少なくとも答え自体で問題解決する方法を示します
paper1111 2017

追加されたデモ:)申し訳ありません@ paper1111
TomaszŻmudaSep

1
連携するには、ファイルを使用しているすべてのプロセスが必要です。OPの元の問題に適用される可能性は低いです。
ハリージョンストン

2

オンラインバックアップアーカイブにPDFをアップロードする必要がありました。ただし、ユーザーがファイルを別のプログラム(PDFリーダーなど)で開いている場合、バックアップは失敗します。私は急いで、このスレッドで上位の回答のいくつかを試みましたが、それらを機能させることができませんでした。私にとってうまくいったことは、PDFファイルを独自のディレクトリに移動しようとしていたことです。ファイルが別のプログラムで開かれている場合、これは失敗し、移動が成功した場合、別のディレクトリに移動された場合のように、復元操作は必要ありません。他の人の特定のユースケースに役立つ可能性がある場合に備えて、私の基本的なソリューションを投稿したいと思います。

string str_path_and_name = str_path + '\\' + str_filename;
FileInfo fInfo = new FileInfo(str_path_and_name);
bool open_elsewhere = false;
try
{
    fInfo.MoveTo(str_path_and_name);
}
catch (Exception ex)
{
    open_elsewhere = true;
}

if (open_elsewhere)
{
    //handle case
}

0

これがWTF反射をトリガーするかどうかを確認したいと思います。コンソールアプリからPDFドキュメントを作成して起動するプロセスがあります。ただし、ユーザーがプロセスを複数回実行し、以前に生成されたファイルを最初に閉じずに同じファイルを生成すると、アプリが例外をスローして終了するという脆弱性に対処していました。ファイル名は販売見積番号に基づいているため、これはかなり頻繁に発生しました。

このように見苦しい方法で失敗するのではなく、自動インクリメントファイルのバージョン管理に依存することにしました。

private static string WriteFileToDisk(byte[] data, string fileName, int version = 0)
{
    try
    {
        var versionExtension = version > 0 ? $"_{version:000}" : string.Empty;
        var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{fileName}{versionExtension}.pdf");
        using (var writer = new FileStream(filePath, FileMode.Create))
        {
            writer.Write(data, 0, data.Length);
        }
        return filePath;
    }
    catch (IOException)
    {
        return WriteFileToDisk(data, fileName, ++version);
    }
}

おそらく、catchブロックをさらに注意して、正しいIOExceptionを確実にキャッチできるようにすることができます。これらのファイルはとにかく一時的なものであることを意図しているので、起動時にアプリストレージを消去することもできます。

これは、単にファイルが使用されているかどうかを確認するというOPの質問の範囲を超えていることに気づきましたが、これは確かに、私がここに到着したときに解決しようとしていた問題なので、おそらく他の誰かに役立つでしょう。


0

このようなものが役に立ちますか?

var fileWasWrittenSuccessfully = false;
while (fileWasWrittenSuccessfully == false)
{
    try
    {
        lock (new Object())
        {
            using (StreamWriter streamWriter = new StreamWriter(filepath.txt"), true))
            {
                streamWriter.WriteLine("text");
            }
        }

        fileWasWrittenSuccessfully = true;
    }
    catch (Exception)
    {

    }
}

-2

ファイルを一時ディレクトリに移動/コピーしてみてください。可能であれば、ロックはなく、ロックを取得せずに一時ディレクトリで安全に作業できます。それ以外の場合は、x秒後にもう一度移動してみてください。


@jcolebrandは何をロックしますか?あなたがコピーしたもの?または、一時ディレクトリに配置したものですか?
Cullub 14

5
ファイルをコピーし、他の誰も作業していないことを期待していて、一時ファイルを使用する場合、コピーした直後に誰かがファイルをロックすると、データが失われる可能性があります。
jcolebrand 2014

-3

この回避策を使用しますが、IsFileLocked関数を使用してファイルのロックを確認してからファイルを開くまでの時間に余裕があります。このタイムスパンでは、他のスレッドがファイルを開くことができるため、IOExceptionが発生します。

だから、私はこれのために追加のコードを追加しました。私の場合、XDocumentをロードします。

        XDocument xDoc = null;

        while (xDoc == null)
        {
            while (IsFileBeingUsed(_interactionXMLPath))
            {
                Logger.WriteMessage(Logger.LogPrioritet.Warning, "Deserialize can not open XML file. is being used by another process. wait...");
                Thread.Sleep(100);
            }
            try
            {
                xDoc = XDocument.Load(_interactionXMLPath);
            }
            catch
            {
                Logger.WriteMessage(Logger.LogPrioritet.Error, "Load working!!!!!");
            }
        }

どう思いますか?何かを変更できますか?IsFileBeingUsed関数をまったく使用する必要がなかったのでしょうか?

ありがとう


4
IsFileBeingUsedとは何ですか?IsFileBeingUsedに関するソースコード
Kiquenet 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.