24

C#で一時ファイルを削除する簡単なプログラムを作成しました(主要なプロジェクトではなく、楽しみのために)、ロックされたファイル(使用中)の問題が発生しています。通常、これらのファイルをどのように除外しますか? 参考までに、次のエラーが表示されます。

別のプロセスによって使用されているため、プロセスはファイル 'ExchangePerflog_8484fa31c65c7a31cfcccd43.dat' にアクセスできません。

コード:

static void Main(string[] args)
    {
        string folderPath = string.Empty;
        folderPath = System.Environment.GetEnvironmentVariable("temp");
        deleteFilesInDirectory(folderPath);
    }

    public static void deleteFilesInDirectory(string folderPath) 
    {

        try
        {
            var dir = new DirectoryInfo(folderPath);
            dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly;
            dir.Delete(true);
            MessageBox.Show(folderPath + " has been cleaned.");
        }
        catch (System.IO.IOException ex)
        {
            MessageBox.Show(ex.Message); 
            return;

        } 
    }     
4

7 に答える 7

21

説明

別のプロセスで現在使用されているファイルを削除する方法はありません。ただし、ファイルがロックされなくなるまで待つことができます。

このメソッドでファイルのロックが解除されるまで while ループをチェックインします

protected virtual bool IsFileLocked(FileInfo file)
{
    FileStream stream = null;

    try
    {
        stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
    }
    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;
    }
    finally
    {
        if (stream != null)
            stream.Close();
    }

    //file is not locked
    return false;
}

サンプル

FileInfo file = new FileInfo("PathToTheFile");
while (IsFileLocked(file))
    Thread.Sleep(1000);
file.Delete();

アップデート

ロックされたファイルをスキップしたい場合は、これを行うことができます。

//
var dir = new DirectoryInfo(folderPath);
foreach(var file in dir.GetFiles()) {
    try
    {
        file.Delete();
    }
    catch (IOException)
    {
        //file is currently locked
    }
}
于 2012-05-08T18:58:53.427 に答える
7

さて、私は同様の問題に遭遇しました。ファイルを削除した直後にディレクトリを削除しようとすると、GC に強制的に現在のスレッドからファイル ハンドルを解放させる必要があります。

public void DisposeAfterTest(string filePath)
    {

        if (File.Exists(filePath))
        {
            File.Delete(filePath);
        }

        GC.Collect();
        GC.WaitForPendingFinalizers();

        if (Directory.Exists(this.TempTestFolderPath))
        {
            Directory.Delete(this.TempTestFolderPath, true);
        }

    }
于 2016-09-27T14:17:41.607 に答える
7

次のコードを試してください。ファイルを削除する前に次の 2 行を追加するだけです。

GC.Collect();
GC.WaitForPendingFinalizers();
于 2016-02-04T08:01:09.637 に答える
1

ファイルが使用中かどうかを事前に知る方法はないと思います。ファイルの排他ロックを取得しようとすることができます。しかし、そうすると、ある例外を別の例外と交換することになります。

これらが開いているファイルである場合は、それらを閉じる方法を改善できないかどうかを確認してください。それよりも複雑な場合は、「削除するリスト」を維持し、成功するまで削除を再試行し続けることができます (同時コレクションを持つ別のスレッドで)。

また、使用中のファイルを強制的に削除する方法があるとは思いません。

于 2012-05-08T18:57:43.977 に答える
0

呼び出す必要があるメソッドは 1 つだけです。つまり、WipeFile で、コードは次のとおりです。したがって、実際に行う必要があるのは、WipeFile を呼び出して、削除するファイルのフル パスと、上書きする回数を指定することだけです。

public void WipeFile(string filename, int timesToWrite)
{
    try
    {
        if (File.Exists(filename))
        {
            // Set the files attributes to normal in case it's read-only.

            File.SetAttributes(filename, FileAttributes.Normal);

            // Calculate the total number of sectors in the file.
            double sectors = Math.Ceiling(new FileInfo(filename).Length/512.0);

            // Create a dummy-buffer the size of a sector.

            byte[] dummyBuffer = new byte[512];

            // Create a cryptographic Random Number Generator.
            // This is what I use to create the garbage data.

            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

            // Open a FileStream to the file.
            FileStream inputStream = new FileStream(filename, FileMode.Open);
            for (int currentPass = 0; currentPass < timesToWrite; currentPass++)
            {
                UpdatePassInfo(currentPass + 1, timesToWrite);

                // Go to the beginning of the stream

                inputStream.Position = 0;

                // Loop all sectors
                for (int sectorsWritten = 0; sectorsWritten < sectors; sectorsWritten++)
                {
                    UpdateSectorInfo(sectorsWritten + 1, (int) sectors);

                    // Fill the dummy-buffer with random data

                    rng.GetBytes(dummyBuffer);

                    // Write it to the stream
                    inputStream.Write(dummyBuffer, 0, dummyBuffer.Length);
                }
            }

            // Truncate the file to 0 bytes.
            // This will hide the original file-length if you try to recover the file.

            inputStream.SetLength(0);

            // Close the stream.
            inputStream.Close();

            // As an extra precaution I change the dates of the file so the
            // original dates are hidden if you try to recover the file.

            DateTime dt = new DateTime(2037, 1, 1, 0, 0, 0);
            File.SetCreationTime(filename, dt);
            File.SetLastAccessTime(filename, dt);
            File.SetLastWriteTime(filename, dt);

            // Finally, delete the file

            File.Delete(filename);

            WipeDone();
        }
    }
    catch(Exception e)
    {
        WipeError(e);
    }
}

プロセス中に何が起こっているかを追跡できるように、いくつかのイベントを追加しました。

  • PassInfoEvent - 実行中のパスと実行するパスの総数を返します。
  • SectorInfoEvent - 書き込まれているセクターと、書き込まれるセクターの総数を返します。
  • WipeDoneEvent - ワイプ プロセスが完了したことを示すインジケーター。
  • WipeErrorEvent - 何か問題が発生した場合に例外を返します。

.NET を使用してファイルを安全に削除する

于 2016-09-27T14:21:09.430 に答える
0

以下のコードは、ロックされたファイルを除くディレクトリとそのすべてのサブディレクトリからファイルを削除し、削除されていないファイルのリストを取得します。現在のディレクトリのみを考慮する場合は、SearchOption を TopDirectoryOnly に変更できます。

string []files = Directory.GetFiles(dirPath,"*.*", SearchOption.AllDirectories); //this gets the files in all subdirectories as well
List<string> lockedFiles = new List<string>();
foreach(string file in files) 
{    
    try    
    {        
        file.Delete();    
    }    
    catch (IOException)    
    {        
        lockedFiles.Add(file);    
    }
}
于 2016-02-04T08:43:12.203 に答える