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


84

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

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블록 에서 삭제합니다 .


3
당신은 ( "응용 프로그램 데이터에서) 삭제됩니다 자신의"임시 "폴더를 만들 수 있지만, 아마도 모든 참조를 변경하는 ballache, 좋은 질문이 될 것입니다
Sayse

질문은 WPF와 관련이 없으며 태그가 제거되었습니다. 또한 삭제하지 않고 임시 파일을 너무 많이 생성하는 코드를 수정하지 않는 이유는 무엇입니까?
Dennis

1
@Sayse Cursor.LoadFromStream임시 파일을 생성하는 WPF이기 때문에 그렇게 할 수 없습니다 . @Dennis WPF의 Cursor.LoadFromStream클래스 와 관련이 있습니다. 삭제하지 않고 너무 많은 임시 파일을 생성하는 문제가되는 코드는 내 소유가 아닐 수도 있으며 여전히 예외를 해결해야합니다.
Omer Raviv 2013-08-21

이러한 모든 임시 파일을 남기고있는 응용 프로그램을 찾을 수 있습니까? 귀하의 응용 프로그램입니까? WPF가 이러한 임시 파일 자체를 만드는 경우 더 이상 필요하지 않을 때 삭제한다는 것을 확인 했습니까?
Ashigore

2
@OmerRaviv 저는 IOE를 시도 / 캐치하고 사용자에게 임시 파일을 삭제하고 다시 시도
할지 묻는 것이라고 생각

답변:


15

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

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;

2
나는 당신이 제안한대로 try / catch로 갈 것입니다. 제안한 부울 테스트는 실제로 잘못되었습니다. % TEMP % 폴더에 GetTempFileName ()이 사용하는 "tmpXXXX.tmp"형식의 파일 외에 다른 파일이있을 수 있으므로 실제로 문제가 없을 때 테스트가 true를 반환 할 수 있습니다. 문제가있을 때 거짓.
Omer Raviv 2013-08-21

이 테스트는 임시 폴더 (올바른 임시 폴더가 아닐 수 있음을 인정하지만)에서 "*"모든 파일을 찾고 65535와 같은지 확인하고 확장명이 있는지 여부에 관계없이 모든 파일을 찾을 수 있도록 설계되었습니다.
Sayse

하루보다 오래된 모든 파일을 삭제할 수 있습니다. 하루보다 오래된 임시 파일은 다른 응용 프로그램에서 사용하지 않을 가능성이 높습니다.
JT Taylor

2
선택적 검사의 또 다른 요점입니다. 빌드 서버에서이 문제가 발생했을 때 임시 디렉토리에 65535 개 이상의 파일이있었습니다. 이 개수는 임시 파일을 만드는 유일한 것이 Path 도우미 클래스를 통하는 경우에만 작동합니다.
rshadman

36

프로덕션 환경에서 또는 변경할 수없는 앱 에서 이런 일이 발생하는 경우 빠른 해결 방법은 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


5

마지막에 사용한 코드는 다음과 같습니다. 호출 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);
        }
    }

2

해결책 :

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

자신의 임시 디렉토리를 사용하는 것이 반드시 해결책은 아닙니다. API를 사용하여 임시 파일 이름을 생성하지만 내 디렉토리에 씁니다. 불행히도 그것조차 실패합니다.
George Mauer 2013

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

1

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

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

좋은 생각이지만 불행히도 내 앱은 다른 확장과 평화롭게 공존해야하는 Visual Studio 확장이며, 이로 인해 다른 확장의 동작이 의도 치 않게 손상 될 수 있습니다.
Omer Raviv 2013-08-21

이 솔루션은 이러한 모든 파일을 남기는 자체 프로그램 인 경우 도움이되지 않습니다. 새 디렉토리가 채워질 뿐이며 응용 프로그램에 특정한 폴더라도 파일이 무엇인지 모를 때 폴더에서 파일을 임의로 삭제하는 것은 좋지 않습니다.
Ashigore

@Ashigore 예, 분명히 그가 만든 버그를 수정하지는 않습니다. 특히 what if they are regularly running some other piece of software that makes frequent calls to GetTempFileName.
Ed Chapel

@OmerRaviv이 정보는 도움이됩니다. 실제로 이것은이 시나리오에서 작동하지 않습니다.
Ed Chapel

1
죄송합니다 @EdChapel, SO가 내 투표를 잠갔으므로 답변을 편집하지 않으면 제거 할 수 없습니다.
Gerardo Grignoli

1

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.