내 고객 중 한 명이 내 제품을 사용하려고 할 때마다 예외가 발생했습니다. 발생한 예외의 호출 스택을 얻었습니다. 맨 위는 다음과 같습니다.
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
).
반면에 자신의 코드에서이 문제가 발생하고 다시 발생하지 않도록하려면 다음을 수행하십시오.
- 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 파일이 유출 된 것은 이미 끔찍한 일입니다.
- 임시 파일을 유출하지 마십시오!
앱에서 모든 행복한 경로와 불행한 경로 (예 : 예기치 않은 예외)를 다시 확인하세요. 각 FileStream을 올바르게 처리하고 finally 블록에서 임시 파일을 삭제하고 있는지 확인합니다.
- 임시 폴더 정리
지금 정리하고 시스템 관리자에게 정기적으로 정리하도록 교육하십시오. 모든 앱을 신뢰할 수는 없기 때문입니다. 내 서버에서 다음을 사용하여이 작업을 자동화합니다.
- 글로벌 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);
}
}
답변
해결책 :
- 오른쪽에있는 거. 너무 많은 임시 파일을 생성하고 삭제하지 않는 응용 프로그램을 감지합니다. 같은 유틸리티
Process monitor
가 도움이 될 것입니다. 그런 다음 응용 프로그램을 수정하거나 버리십시오. 그리고 예, 이것은 귀하의 응용 프로그램 일 수 있습니다. 그래서 악의 근원을 찾아 보라고 권합니다. - 가장 쉬운 방법입니다. 자신의 임시 디렉토리를 사용하십시오. 코드에서 파일을 만드는 경우에는 도움이되지 않습니다.
- 가장 못생긴 사람. 애플리케이션에서 임시 디렉토리를 지 웁니다. 결과에 대해 절대적으로 옳습니다. 다른 응용 프로그램을 중단 할 수 있습니다.
답변
// one more implementation
string GetTempFileName()
{
return Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
}
답변
Sayse가 제안 했듯이 앱이 시작될 때 % TEMP % 환경 변수를 설정해 볼 수 있습니다.
Environment.SetEnvironmentVariable("TEMP", "<dir>");
답변
이 문제를 경험하고 넘쳐나는 임시 폴더를 찾을 수없는 다른 사람은 “C : / Windows / Temp”폴더를 확인하십시오. 이 폴더를 청소하면 문제가 해결되었습니다.