System.IO.IOException: «Файл существует» при использовании System.IO.Path.GetTempFileName () - разрешения?

Один из моих клиентов получал исключение всякий раз, когда пытался использовать мой продукт. Я получил callstack произошедшего исключения, вершина которого:

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, и он, конечно, не виноват - он создает временный файл, но затем удаляет его в ---- +: = 2 =: + ---- block.

67 голосов | спросил Omer Raviv 21 AM000000100000003431 2013, 10:55:34

6 ответов


0

Как я уже упоминал в своем последнем комментарии, я думаю, что ваш единственный безопасный способ сделать это - спросить пользователя, хотят ли вы, чтобы вы удалили файлы, и повторите попытку. Крайне важно , чтобы вы внесли вклад пользователей в это, таким образом, на свой страх и риск. В моей голове что-то похожее на.

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;
ответил Sayse 21 AM000000110000002331 2013, 11:20:23
0

Если это происходит с вами в производственной среде или с приложением, которое вы не можете изменить, быстрое решение состоит в том, чтобы очистить папку Temp.

В зависимости от пользователя, который запускает приложение, вы должны либо

  • Пусто C:\Windows\Temp (для IIS или служб, работающих в LocalSystem аккаунт)
  • Или %temp% для локально зарегистрированных пользователей (для меня это C:\Users\MyUserName\AppData\Local\Temp).

С другой стороны, если ваш собственный код выдает это, и вы хотите, чтобы это больше не повторилось:

  1. Не используйте System.IO.Path.GetTempFileName ()!

GetTempFileName() - это обертка для Win32 Api двух десятилетий . Он генерирует имена файлов, которые будут очень легко сталкиваться. Он обходит эти коллизии путем интенсивного зацикливания в файловой системе, перебирая возможные имена файлов от "%temp%\tmp0000.tmp" до "tmpFFFF.tmp" и пропустить уже существующие. Это интенсивный, медленный и откровенно ужасный алгоритм ввода-вывода. Кроме того, использование только 4 шестнадцатеричных символов - вот что делает искусственное ограничение в 65536 файлов перед сбоем.

Альтернатива - генерировать имена файлов, которые не будут конфликтовать. Например, давайте повторно используем логику GUID's: 32 шестнадцатеричные цифры почти никогда не будут конфликтовать.

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

Это расширяет лимит с 65 000 до 4 000 000 файлов максимум (теоретически) ... Конечно, утечка 65 000 файлов уже ужасна, так что ...

  1. Не пропускайте временные файлы!

Дважды проверьте ваше приложение на наличие счастливых и несчастных путей (например, неожиданных исключений). Убедитесь, что он корректно удаляет каждый FileStream и удаляет временные файлы в блоках "Наконец".

  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

ответил Gerardo Grignoli 18 Maypm18 2018, 17:05:58
0

Вот код, который я использовал в конце и поместил в начале кода инициализации моего приложения, перед любыми вызовами 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);
        }
    }
ответил Omer Raviv 21 PM00000030000000631 2013, 15:49:06
0

Решения:

  1. Правильный. Определите, какое приложение создает столько временных файлов, а не удаляя их. Утилиты, такие как Process monitor должен вам помочь. Затем либо исправьте приложение, либо выбросьте его. И да, это может быть ваше приложение. Вот почему я рекомендую вам обнаружить источник зла.
  2. Самый простой. Используйте свой собственный временный каталог. Это не поможет, если файлы создаются из вашего кода.
  3. Самый уродливый. Очистите временную директорию от вашего приложения. Вы абсолютно правы в отношении последствий - вы можете сломать другое приложение.
ответил Dennis 21 AM000000110000002231 2013, 11:11:22
0

Как и Sayse , вы можете попытаться установить переменную среды% TEMP% при запуске приложения.

Environment.SetEnvironmentVariable("TEMP", "<dir>");
ответил Ed Chapel 21 AM000000110000005431 2013, 11:06:54
0

Для всех, кто столкнулся с этой проблемой и не может найти переполненную временную папку - Проверьте папку «C: /Windows /Temp». Очистка этой папки решила мои проблемы.

ответил Fredrik Fahlman 7 PM00000040000005631 2017, 16:29:56

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132