Saltar al contenido

System.IO.IOException: “El archivo existe” cuando se usa System.IO.Path.GetTempFileName () – ¿resoluciones?

Solución:

Si esto te está sucediendo en un entorno de producción o con una aplicación que no puede cambiar, la solución rápida es vaciar la carpeta Temp.

Dependiendo del usuario que esté ejecutando la aplicación, debería

  • Vacío C:WindowsTemp (para IIS o servicios que se ejecutan bajo LocalSystem cuenta)
  • O %temp% para los usuarios que han iniciado sesión localmente (que para mí es C:UsersMyUserNameAppDataLocalTemp).

Por otro lado, si su propio código arroja esto y desea evitar que esto vuelva a suceder nunca más:

  1. ¡No use System.IO.Path.GetTempFileName ()!

GetTempFileName() es un contenedor de Win32 Api de hace dos décadas. Genera nombres de archivos que colisionarán muy fácilmente. Evita esas colisiones realizando un gran bucle en el sistema de archivos, iterando posibles nombres de archivo de "%temp%tmp0000.tmp" para "tmpFFFF.tmp" y omitiendo los ya existentes. Este es un algoritmo de E / S intensivo, lento y francamente terrible. Además, el uso de solo 4 caracteres hexadecimales es lo que hace que el límite artificial de 65536 archivos antes de fallar.

La alternativa es generar nombres de archivo que no colisionen. Por ejemplo, reutilicemos GUID's lógica: 32 dígitos hexadecimales casi nunca colisionarán.

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

Esto expande el límite de 65k a 4k millones de archivos como máximo (teóricamente) … Por supuesto, haber filtrado 65k archivos ya es terrible, así que …

  1. ¡No pierda archivos temporales!

Verifique su aplicación para ver todos los caminos felices e infelices (como excepciones inesperadas). Asegúrese de que esté desechando correctamente cada FileStream y eliminando los archivos temporales en los bloques Finalmente.

  1. Limpiar la carpeta temporal

Límpielo ahora y eduque al administrador del sistema para que lo limpie periódicamente, porque no puede confiar en todas las aplicaciones en la naturaleza. En mis propios servidores, automatizaría esta tarea usando:

  • Para Windows Temp global

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

  • Para el usuario actual:

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

Como mencioné en mi último comentario, creo que la única forma segura de hacerlo es preguntarle al usuario si quiere que elimine archivos y vuelva a intentarlo. Está imperativo que obtenga la opinión de los usuarios en esto, de esta manera es bajo su propio riesgo. En mi cabeza es algo similar a.

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

}

Una verificación opcional para asegurarse de que podría ser,

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

Aquí está el código que usé al final, y puse temprano en la ruta del código de inicialización de mi aplicación, antes de cualquier llamada a Cursor.LoadFromStream puede ocurrir:

    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);
        }
    }
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags : / /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *