development

System.IO.IOException : System.IO.Path.GetTempFileName ()을 사용할 때 "파일이 있습니다"-해결 방법?

big-blog 2020. 10. 22. 08:18
반응형

System.IO.IOException : System.IO.Path.GetTempFileName ()을 사용할 때 "파일이 있습니다"-해결 방법?


내 고객 중 한 명이 내 제품을 사용하려고 할 때마다 예외가 발생했습니다. 발생한 예외의 호출 스택을 얻었습니다. 맨 위는 다음과 같습니다.

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.__Error.WinIOError()
   at System.IO.Path.GetTempFileName()
   at System.Windows.Input.Cursor.LoadFromStream(Stream cursorStream)
   at System.Windows.Input.Cursor..ctor(Stream cursorStream)

인터넷 검색 을 통해 % TEMP % 폴더에 65535 개 이상의 임시 파일이있을 때이 예외가 발생한다는 블로그 게시물많이 있으며 해결책은 단순히 이전 임시 파일을 지우는 것입니다. 고객에게 그렇게하도록 요청할 수 있지만 이것은 일시적인 해결책 일 수 있습니다. GetTempFileName을 자주 호출하는 다른 소프트웨어를 정기적으로 실행하는 경우 문제가 반복적으로 발생하는 경우 어떻게합니까?

어떻게 든 다른 것을 손상시킬 수 있으므로 프로그래밍 방식으로 % TEMP % 폴더를 지울 수 없으며 GetTempFileName을 호출하고 대신 내 임시 폴더를 사용하는 것을 피할 수 없습니다. 저가 아니라 WPF 코드를 호출합니다.

이에 대한 영구적 인 해결책이 있습니까?

업데이트 : % TEMP % 폴더에 로그 파일이 넘쳐나는 문제는 내 코드로 인한 것이 아니며 고객 컴퓨터의 다른 타사 응용 프로그램으로 인한 것임을 확인했습니다. 나는 또한 구현을 살펴 보았고 Cursor.LoadFromStream분명히 잘못이 아닙니다. 임시 파일을 생성하지만 finally블록 에서 삭제합니다 .


마지막 댓글에서 언급했듯이 이렇게하는 유일한 안전한 방법은 사용자에게 파일 삭제를 원하는지 물어보고 다시 시도하는 것입니다. 이다 절대적으로 당신이로 자신의 위험에있다 이런 식으로 사용자의 입력을 얻을. 내 머릿속에는 비슷한 것이 있습니다.

public Stream GetStream(Stream cursorStream)
{
    try
    {
       //getting stream
    }
    catch(IOE)
    {
        MessageBox.Show(this, "Unable to get stream, your temporary
                              folder may be full, do you want to try deleting 
                                some and try again?");
         if(yes)
         try
         {
             //delete and try again
             return GetStream(cursorStream);
         }
         catch(IOE)
          {
                //no luck
           }
          else
              return null;
    }

}

확인하기위한 선택적 검사는 다음과 같습니다.

Directory.EnumerateFiles(Path.GetTempPath(), "*", SearchOption.TopLevelOnly)
  .Count() == ushort.MaxValue;

프로덕션 환경에서 또는 변경할 수없는 앱 에서 이런 일이 발생하는 경우 빠른 해결 방법은 Temp 폴더를 비우는 것입니다.

응용 프로그램을 실행하는 사용자에 따라 다음 중 하나를 수행해야합니다.

  • 비어 있음 C:\Windows\Temp(IIS 또는 LocalSystem계정으로 실행되는 서비스의 경우 )
  • 또는 %temp%로컬로 로그온 한 사용자의 경우 (저는 C:\Users\MyUserName\AppData\Local\Temp).

반면에 자신의 코드에서이 문제가 발생하고 다시 발생하지 않도록하려면 다음을 수행하십시오.

  1. System.IO.Path.GetTempFileName ()을 사용하지 마십시오!

GetTempFileName()20 년 된 Win32 Api 의 래퍼입니다 . 매우 쉽게 충돌하는 파일 이름을 생성합니다. 그것은 크게, 파일 시스템에서 루프에서 가능한 파일 이름을 반복하여 이러한 collitions을 우회 "%temp%\tmp0000.tmp""tmpFFFF.tmp"이미 기존 건너 뛰는. 이것은 I / O 집약적이고 느리고 솔직히 끔찍한 알고리즘입니다. 또한 4 개의 16 진수 문자 만 사용하면 실패하기 전에 65536 개의 파일을 인위적으로 제한합니다.

대안은 충돌하지 않는 파일 이름을 생성하는 것입니다. 예를 들어, GUID's로직을 재사용 할 수 있습니다 . 16 진수 32 자리는 거의 충돌하지 않습니다.

private string GetTempFileName()
{
    return Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
}
// Sample: c:\Windows\Temp\2e38fe87-f6bb-4b0d-90b3-2d07016324c1

This expands the limit from 65k to 4k millions files max (theoretically)... Of course, having leaked 65k files is already terrible, so...

  1. Do not leak temp files!

Double check your app for all happy and unhappy paths (like unexpected exceptions). Ensure it's correctly disposing each FileStream and deleting the temp files in Finally blocks .

  1. Clean the temp folder

Clean it now, and educate the system administrator to clean it periodically, because you can't trust every app in the wild. On my own servers I would automate this task using:

  • For global Windows\Temp

schtasks /Create /TR "cmd /c call DEL /F /S /Q %^TEMP%" /TN "Delete Global Temp Files" /sc WEEKLY /ST 12:00 /ru system

  • For current user:

schtasks /Create /TR "cmd /c call DEL /F /S /Q %^TEMP%" /TN "Delete %username% Temp Files" /sc WEEKLY /ST 12:00


Here's the code I used in the end, and put early in my app's initialization code-path, before any calls to Cursor.LoadFromStream might occur:

    private void WarnUserIfTempFolderFull()
    {
        string tempFile = null;
        try
        {
            tempFile = Path.GetTempFileName();
        }
        catch (IOException e)
        {
            string problem = "The Temporary Folder is full.";

            string message = "{ProductName} has detected that the Windows Temporary Folder is full. \n" + 
                             "This may prevent the {ProductName} from functioning correctly.\n" + 
                             "Please delete old files in your temporary folder (%TEMP%) and try again.";

            Logger.Warn(problem);

            MessageBox.Show(message, caption: problem);
        }
        finally
        {
            if (tempFile != null) File.Delete(tempFile);
        }
    }

Solutions:

  1. The right one. Detect which application is producing so many temporary files and not deleting them. Utilities like Process monitor should help you. Then either fix the application or throw it away. And yes, this might be your application. that's why I'd recommend you to detect the source of evil.
  2. The easiest one. Use your own temporary directory. This won't help if the files are being created from your code.
  3. The ugliest one. Clear the temporary directory from your application. You're absolutely right about the consequences - you could break another application.

As Sayse suggested, you might try setting the %TEMP% environment variable when your app launches.

Environment.SetEnvironmentVariable("TEMP", "<dir>");

For anyone else who has experienced this problem and can't find any overflowing temp-folder - Check the "C:/Windows/Temp"-folder. Cleaning this folder solved my problems.

참고URL : https://stackoverflow.com/questions/18350699/system-io-ioexception-the-file-exists-when-using-system-io-path-gettempfilena

반응형