Al fin luego de mucho luchar pudimos dar con la contestación de este asunto que algunos de nuestros usuarios de esta web han tenido. Si tienes algún detalle que aportar puedes compartir tu conocimiento.
Solución:
Si esto te está pasando 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, debe
- Vacío
C:WindowsTemp
(para IIS o servicios que se ejecutan bajoLocalSystem
cuenta) - O
%temp%
para usuarios registrados localmente (que para mí esC:UsersMyUserNameAppDataLocalTemp
).
Por otro lado, si su propio código arroja esto y desea evitar que esto vuelva a suceder:
- ¡No utilice System.IO.Path.GetTempFileName()!
GetTempFileName()
es un contenedor de Win32 Api de dos décadas de antigüedad. Genera nombres de archivo que colisionarán muy fácilmente. Elude esas colisiones al realizar un bucle intensivo en el sistema de archivos, iterando los posibles nombres de archivo de "%temp%tmp0000.tmp"
para "tmpFFFF.tmp"
y saltándose los ya existentes. Este es un algoritmo intensivo de E/S, lento y francamente terrible. También usar 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 archivos que no entren en conflicto. 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 amplía 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…
- ¡No filtre archivos temporales!
Verifique dos veces 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.
- 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 WindowsTemp 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 los archivos e intentarlo de nuevo. Está imperativo que obtenga la entrada 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 podría ser,
Directory.EnumerateFiles(Path.GetTempPath(), "*", SearchOption.TopLevelOnly)
.Count() == ushort.MaxValue;
Aquí está el código que usé al final, y lo puse al principio de 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);
Sección de Reseñas y Valoraciones
Nos puedes añadir valor a nuestro contenido informacional aportando tu veteranía en las explicaciones.