Programing

.NET의 파일에 대한 액세스가 거부되었는지 어떻게 쉽게 확인할 수 있습니까?

crosscheck 2020. 8. 22. 08:00
반응형

.NET의 파일에 대한 액세스가 거부되었는지 어떻게 쉽게 확인할 수 있습니까?


기본적으로 실제로 파일을 열기 전에 파일을 열 수있는 권한이 있는지 확인하고 싶습니다. 꼭 필요한 경우가 아니면이 수표에 try / catch를 사용하고 싶지 않습니다. 미리 확인할 수있는 파일 액세스 속성이 있습니까?


나는 과거에이 일을 수없이 해왔고, 거의 매번 시도조차하는 것이 잘못되었습니다.

파일 권한 (파일 존재 여부 포함)은 휘발성 이며 언제든지 변경 될 수 있습니다. Murphy의 법칙 덕분에 특히 파일을 확인하고 파일을 열려고 할 때 사이의 짧은 기간 포함됩니다. 먼저 확인해야하는 영역에있는 경우 변경 가능성이 더 높습니다. 그러나 이상하게도 상당히 정적 인 경향이있는 테스트 또는 개발 환경에서는 절대 발생하지 않습니다. 이로 인해 나중에 문제를 추적하기가 어렵고 이러한 종류의 버그가 프로덕션에 쉽게 적용됩니다.

이것이 의미하는 바는 검사에도 불구하고 파일 권한이나 존재가 나쁜 경우 예외를 처리 할 수 ​​있어야한다는 것입니다. 사전에 파일 권한을 확인하든 안하든 예외 처리 코드가 필요 합니다. 예외 처리 코드는 존재 또는 권한 검사의 모든 기능을 제공 합니다. 또한 이와 같은 예외 처리기는 느린 것으로 알려져 있지만 디스크 I / o가 훨씬 더 느립니다 ... 훨씬 느리고 ... .Exists () 함수를 호출하거나 권한을 확인하면 추가 트립이 발생 한다는 점을 기억하는 것이 중요합니다. 파일 시스템 밖으로.

요약하면 파일을 열기 전에 초기 검사는 중복되고 낭비입니다. 예외 처리에 대한 추가 이점은 없습니다. 실제로 성능에 도움이되지 않고 손상을 입히고 유지 관리해야하는 더 많은 코드 측면에서 비용을 추가하고 코드에 미묘한 버그를 유발할 수 있습니다. 초기 확인을 수행하는 데는 전혀 이점이 없습니다. 대신, 여기서 올바른 것은 파일을 열고 실패 할 경우 좋은 예외 처리기에 노력을 기울이는 것입니다. 파일이 존재하는지 여부를 확인하는 경우에도 마찬가지입니다. 이 추론은 모든 휘발성 자원에 적용됩니다 .


비슷한 문제로 여기에 오는 다른 사람을위한 빠른 팁 :

DropBox와 같은 웹 동기화 앱에주의하십시오. 방금 2 시간 동안 "using"문 (Dispose 패턴)이 .NET에서 손상되었다고 생각했습니다.

결국 Dropbox가 파일을 동기화하기 위해 백그라운드에서 지속적으로 파일을 읽고 쓰는 것을 깨달았습니다.

내 Visual Studio 프로젝트 폴더가 어디에 있는지 추측합니까? 물론 "내 Dropbox"폴더 안에 있습니다.

따라서 디버그 모드에서 응용 프로그램을 실행할 때 읽고 쓰는 파일도 DropBox 서버와 동기화되기 위해 계속해서 DropBox에 의해 액세스되었습니다. 이로 인해 잠금 / 액세스 충돌이 발생했습니다.

그래서 적어도 이제 더 강력한 파일 열기 함수 (예 : 여러 번 시도하는 TryOpen ())가 필요하다는 것을 알고 있습니다. 나는 그것이 이미 프레임 워크의 내장 된 부분이 아니라는 것에 놀랐다.

[최신 정보]

내 도우미 기능은 다음과 같습니다.

/// <summary>
/// Tries to open a file, with a user defined number of attempt and Sleep delay between attempts.
/// </summary>
/// <param name="filePath">The full file path to be opened</param>
/// <param name="fileMode">Required file mode enum value(see MSDN documentation)</param>
/// <param name="fileAccess">Required file access enum value(see MSDN documentation)</param>
/// <param name="fileShare">Required file share enum value(see MSDN documentation)</param>
/// <param name="maximumAttempts">The total number of attempts to make (multiply by attemptWaitMS for the maximum time the function with Try opening the file)</param>
/// <param name="attemptWaitMS">The delay in Milliseconds between each attempt.</param>
/// <returns>A valid FileStream object for the opened file, or null if the File could not be opened after the required attempts</returns>
public FileStream TryOpen(string filePath, FileMode fileMode, FileAccess fileAccess,FileShare fileShare,int maximumAttempts,int attemptWaitMS)
{
    FileStream fs = null;
    int attempts = 0;

    // Loop allow multiple attempts
    while (true)
    {
        try
        {
            fs = File.Open(filePath, fileMode, fileAccess, fileShare);

            //If we get here, the File.Open succeeded, so break out of the loop and return the FileStream
            break;
        }
        catch (IOException ioEx)
        {
            // IOExcception is thrown if the file is in use by another process.

            // Check the numbere of attempts to ensure no infinite loop
            attempts++;
            if (attempts > maximumAttempts)
            {
                // Too many attempts,cannot Open File, break and return null 
                fs = null;
                break;
            }
            else
            {
                // Sleep before making another attempt
                Thread.Sleep(attemptWaitMS);

            }

        }

    }
    // Reutn the filestream, may be valid or null
    return fs;
}

Here is the solution you are looking for

var fileIOPermission = new FileIOPermission(FileIOPermissionAccess.Read,
                                            System.Security.AccessControl.AccessControlActions.View,
                                            MyPath);

if (fileIOPermission.AllFiles == FileIOPermissionAccess.Read)
{
    // Do your thing here...
}

this creates a new permission of read based on view for path of all files then checks if it's equal to file access read.


First, what Joel Coehoorn said.

Also: you should examine the assumptions that underly your desire to avoid using try/catch unless you have to. The typical reason for avoiding logic that depends on exceptions (creating Exception objects performs poorly) probably isn't relevant to code that's opening a file.

I suppose that if you're writing a method that populates a List<FileStream> by opening every file in a directory subtree and you expected large numbers of them to be inaccessible you might want to check file permissions before trying to open a file so that you didn't get too many exceptions. But you'd still handle the exception. Also, there's probably something terribly wrong with your program's design if you're writing a method that does this.


public static bool IsFileLocked(string filename)
        {
            bool Locked = false;
            try
            {
                FileStream fs =
                    File.Open(filename, FileMode.OpenOrCreate,
                    FileAccess.ReadWrite, FileShare.None);
                fs.Close();
            }
            catch (IOException ex)
            {
                Locked = true;
            }
            return Locked;
        }

public static FileStream GetFileStream(String filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, ref int attempts, int attemptWaitInMilliseconds)
{            
    try
    {
         return File.Open(filePath, fileMode, fileAccess, fileShare);
    }
    catch (UnauthorizedAccessException unauthorizedAccessException)
    {
        if (attempts <= 0)
        {
            throw unauthorizedAccessException;
        }
        else
        {
            Thread.Sleep(attemptWaitInMilliseconds);
            attempts--;
            return GetFileStream(filePath, fileMode, fileAccess, fileShare, ref attempts, attemptWaitInMilliseconds);
        }
    }
}

참고URL : https://stackoverflow.com/questions/265953/how-can-you-easily-check-if-access-is-denied-for-a-file-in-net

반응형