[c#] 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을 호출하고 대신 내 임시 폴더를 사용하는 것을 피할 수 없습니다.

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

업데이트 : % 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

이로 인해 제한이 65,000에서 최대 4 천만 파일로 확장됩니다 (이론적으로) … 물론 65k 파일이 유출 된 것은 이미 끔찍한 일입니다.

  1. 임시 파일을 유출하지 마십시오!

앱에서 모든 행복한 경로와 불행한 경로 (예 : 예기치 않은 예외)를 다시 확인하세요. 각 FileStream을 올바르게 처리하고 finally 블록에서 임시 파일을 삭제하고 있는지 확인합니다.

  1. 임시 폴더 정리

지금 정리하고 시스템 관리자에게 정기적으로 정리하도록 교육하십시오. 모든 앱을 신뢰할 수는 없기 때문입니다. 내 서버에서 다음을 사용하여이 작업을 자동화합니다.

  • 글로벌 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

  • 현재 사용자의 경우 :

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


답변

마지막에 사용한 코드는 다음과 같습니다. 호출 Cursor.LoadFromStream이 발생 하기 전에 앱의 초기화 코드 경로에 초기에 넣었습니다 .

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


답변

해결책 :

  1. 오른쪽에있는 거. 너무 많은 임시 파일을 생성하고 삭제하지 않는 응용 프로그램을 감지합니다. 같은 유틸리티 Process monitor가 도움이 될 것입니다. 그런 다음 응용 프로그램을 수정하거나 버리십시오. 그리고 예, 이것은 귀하의 응용 프로그램 일 수 있습니다. 그래서 악의 근원을 찾아 보라고 권합니다.
  2. 가장 쉬운 방법입니다. 자신의 임시 디렉토리를 사용하십시오. 코드에서 파일을 만드는 경우에는 도움이되지 않습니다.
  3. 가장 못생긴 사람. 애플리케이션에서 임시 디렉토리를 지 웁니다. 결과에 대해 절대적으로 옳습니다. 다른 응용 프로그램을 중단 할 수 있습니다.


답변

// one more implementation
string GetTempFileName()
{
    return Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
}


답변

Sayse가 제안 했듯이 앱이 시작될 때 % TEMP % 환경 변수를 설정해 볼 수 있습니다.

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


답변

이 문제를 경험하고 넘쳐나는 임시 폴더를 찾을 수없는 다른 사람은 “C : / Windows / Temp”폴더를 확인하십시오. 이 폴더를 청소하면 문제가 해결되었습니다.