중인 - c# 파일 열려있는지 확인




파일이 사용 중인지 확인하는 방법이 있습니까? (11)

3-liners를 다루는 것 외에도 참고 용으로 : 전체 정보를 원한다면 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 함수를 통해 다시 시작 관리자 세션에 자원을 등록한 후 RMpROCESS_INFO 배열을 열거하여 특정 파일을 사용중인 응용 프로그램을 확인하기 위해 RmGetList 함수가 호출됩니다.

"Restart Manager 세션"에 연결하여 작동합니다.

재시작 관리자는 세션에 등록 된 자원 목록을 사용하여 어떤 응용 프로그램과 서비스를 종료하고 다시 시작해야하는지 결정합니다. 리소스는 파일 이름, 서비스 약식 이름 또는 실행중인 응용 프로그램을 설명하는 RM_UNIQUE_PROCESS 구조로 식별 할 수 있습니다 .

그것은 당신의 특별한 필요를 위해 조금 과장 되어 있을지도 모른다. .. 그러나 그것이 당신이 원하는 것이면, 계속 나아가고, vs-project를 부여 잡아라 .

C #에서 반복적으로 1 개의 이미지 파일에 액세스해야하는 프로그램을 작성하고 있습니다. 대부분의 경우 작동하지만 컴퓨터가 빠르게 실행되면 파일 시스템에 다시 저장되기 전에 파일에 액세스하려고 시도하고 "다른 프로세스에서 사용중인 파일" 오류가 발생합니다.

이 문제를 해결할 방법을 찾고 싶습니다. 그러나 모든 인터넷 검색은 예외 처리를 사용하여 검사를 생성해야합니다. 이것은 나의 종교에 반하는 것이므로 누군가가 그것을하는 더 좋은 방법이 있는지 궁금해하고 있었습니까?


FileShare.Read 모드로 쓰기 위해 파일을 연 경우 또는 파일에 읽기 전용 속성이있는 경우 코드가 작동하지 않는 문제가 있습니다. 이 수정 된 솔루션은 가장 신뢰할 수있게 작동하며 다음 두 가지 사항을 염두에 두어야합니다 (허용 된 솔루션에서도 마찬가지 임).

  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;
}

내 경험에 따르면, 보통이 작업을 수행하고 파일을 보호하여 멋진 파일을 만든 다음 '보호 된 파일'을 사용합니다. 이와 같이 사용하려는 파일이 하나 뿐인 경우 Jeremy Thompson의 대답에서 설명한 트릭을 사용할 수 있습니다. 그러나 많은 파일에서이 작업을 시도하면 (예를 들어 설치 프로그램을 작성할 때), 상당히 상처를 입을 수 있습니다.

이 문제를 해결할 수있는 매우 우아한 방법은 파일 시스템에 파일 중 하나가 사용될 경우 파일 시스템이 폴더 이름을 변경할 수 없도록하는 것입니다. 동일한 파일 시스템에 폴더를 유지하면 매력처럼 작동합니다.

이것이 악용 될 수있는 분명한 방법을 알고 있어야한다는 점에 유의하십시오. 결국 파일은 잠기지 않습니다. 또한 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이 게시 한 잠금 제안을 계속 사용합니다.


내 라이브러리를 사용하여 여러 앱의 파일에 액세스 할 수 있습니다.

nuget에서 설치할 수 있습니다 : Install-Package Xabe.FileLock

더 자세한 정보가 필요하면 https://github.com/tomaszzmuda/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를 돌려줍니다. 그러나 파일을 업로드하는 앱은 파일 잠금에서도이를 수행해야합니다. object에 액세스 할 수없는 경우 metod는 false를 반환합니다.


스트림을 사용할 수있게되는 즉시 작업을 반환 할 수 있습니다. 단순화 된 솔루션이지만 좋은 출발점입니다. 스레드로부터 안전합니다.

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);
}

아마도 FileSystemWatcher 사용하고 Changed 이벤트를 감시 할 수 있습니다.

나는 이걸 사용하지 않았지만, 그럴만 한 가치가 있을지도 모른다. filesystemwatcher가이 경우 약간 무거 우면 try / catch / sleep 루프를 사용합니다.


의도 한대로 예외를 사용하십시오. 파일이 사용 중임을 수락하고 작업이 완료 될 때까지 반복하여 다시 시도하십시오. 행동하기 전에 상태를 확인하는주기를 낭비하지 않으므로이 방법이 가장 효율적입니다.

아래 함수를 사용하십시오.

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);
}

이 해결 방법을 사용하지만 IsFileLocked 함수로 파일을 검사 할 때와 파일을 열 때 사이에 시간 간격이 있습니다. 이 timespan에서 다른 스레드가 파일을 열 수 있으므로 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 함수를 전혀 사용할 필요가 없었을까요?

감사


파일을 임시 디렉토리로 이동하고 복사하십시오. 할 수 있으면 자물쇠도없고 자물쇠없이 자국내에서 안전하게 일할 수 있습니다. 그렇지 않으면 x 초 후에 다시 이동하십시오.


파일이 잠겨 있는지 확인하려면이 옵션을 사용하십시오.

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");

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");

희망이 도움이!





file-locking