¿Cerrará esta secuencia una cláusula using?


Aparentemente me he metido en un mal hábito de codificación. He aquí un ejemplo del código que he estado escribiendo:

using(StreamReader sr = new StreamReader(File.Open("somefile.txt", FileMode.Open)))
{
    //read file
}
File.Move("somefile.txt", "somefile.bak"); //can't move, get exception that I the file is open

Pensé que debido a que la cláusula using explícitamente llamada Close() y Dispose() en la StreamReader, la FileStream también se cerraría.

La única manera de solucionar el problema que estaba teniendo era cambiando el bloque anterior a este:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
{
  using(StreamReader sr = new StreamReader(fs))
  {
    //read file
  }
}

File.Move("somefile.txt", "somefile.bak"); // can move file with no errors

¿Debería cerrar el StreamReader desechando en el primer bloque también cerrar el FileStream subyacente? O, estaba yo ¿equivocado?

Editar

Decidí publicar el bloque de código ofensivo real, para ver si podemos llegar al fondo de esto. Ahora tengo curiosidad.

Pensé que tenía un problema en la cláusula using, así que expandí todo, y todavía no se puede copiar, cada vez. Creo el archivo en esta llamada de método, por lo que no creo que nada más tenga un controlador abierto en el archivo. También he verificado que las cadenas devueltas de las llamadas Path.Combine son correctas.

private static void GenerateFiles(List<Credit> credits)
{
    Account i;
    string creditFile = Path.Combine(Settings.CreditLocalPath, DateTime.Now.ToString("MMddyy-hhmmss") + ".credits");

    StreamWriter creditsFile = new StreamWriter(File.Open(creditFile, FileMode.Create));

    creditsFile.WriteLine("code\inc");

    foreach (Credit c in credits)
    {
        if (DataAccessLayer.AccountExists(i))
        {
            string tpsAuth = DataAccessLayer.GetAuthCode(i.Pin);
            creditsFile.WriteLine(String.Format("{0}{1}\t{2:0.00}", i.AuthCode, i.Pin, c.CreditAmount));
        }
        else
        {
            c.Error = true;
            c.ErrorMessage = "NO ACCOUNT";
        }

        DataAccessLayer.AddCredit(c);

    }

    creditsFile.Close();
    creditsFile.Dispose();

    string dest =  Path.Combine(Settings.CreditArchivePath, Path.GetFileName(creditFile));
    File.Move(creditFile,dest);
    //File.Delete(errorFile);
}
Author: Dawid Ferenczy, 2009-04-02

5 answers

Sí, StreamReader.Dispose cierra la secuencia subyacente (para todas las formas públicas de crear una). Sin embargo, hay una mejor alternativa:

using (TextReader reader = File.OpenText("file.txt"))
{
}

Esto tiene el beneficio adicional de que abre el flujo subyacente con una sugerencia a Windows de que accederá secuencialmente.

Aquí hay una aplicación de prueba que muestra la primera versión que funciona para mí. No estoy tratando de decir que eso es prueba de nada en particular, pero me encantaría saber lo bien que funciona para usted.

using System;
using System.IO;

class Program
{
    public static void Main(string[] args)
    {
        for (int i=0; i < 1000; i++)
        {
            using(StreamReader sr = new StreamReader
                  (File.Open("somefile.txt", FileMode.Open)))
            {
                Console.WriteLine(sr.ReadLine());
            }
            File.Move("somefile.txt", "somefile.bak");
            File.Move("somefile.bak", "somefile.txt");
        }
    }
}

Si eso funciona, sugiere que tiene algo que ver con lo que haces mientras lees...

Y ahora aquí hay una versión abreviada de su código de pregunta editado, que de nuevo funciona bien para mí, incluso en un recurso compartido de red. Tenga en cuenta que he cambiado FileMode.Create a FileMode.CreateNew, ya que de lo contrario podría todavía haber sido una aplicación con un controlador en el archivo antiguo, potencialmente. ¿Esto te funciona?

using System;
using System.IO;

public class Test
{    
    static void Main()
    {
        StreamWriter creditsFile = new StreamWriter(File.Open("test.txt", 
                                          FileMode.CreateNew));

        creditsFile.WriteLine("code\\inc");

        creditsFile.Close();
        creditsFile.Dispose();

        File.Move("test.txt", "test2.txt");
    }
}
 35
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-17 19:39:27

Nota - sus bloques de uso no necesitan estar anidados en sus propios bloques-pueden ser secuenciales, como en:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
using(StreamReader sr = new StreamReader(fs))
{
    //read file
}

El orden de eliminación en este caso sigue siendo el mismo que los bloques anidados (es decir, el StreamReader seguirá disponiendo antes que el FileStream en este caso).

 10
Author: Not Sure,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-01 21:40:11

Sería intentar utilizar FileInfo.Open() y FileInfo.MoveTo() en lugar de File.Open() y File.Move(). También puede intentar usar FileInfo.OpenText(). Pero estas son solo sugerencias.

 1
Author: MartinStettner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-01 21:53:35

Existe alguna posibilidad de que algo más tenga un bloqueo en algún archivo.txt?

Una simple comprobación de una línea cmd local (al archivo)

net files

Bien puede darte algunas pistas si algo más tiene un candado.

Alternativamente, puede obtener algo como FileMon para tomar aún más detalles y verificar que su aplicación se libera correctamente.

 0
Author: Zhaph - Ben Duguid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-01 21:41:29

Dado que esto no parece ser un problema de codificación, voy a poner mi sombrero de syadmin y ofrecer algunas sugerencias.

  1. Escáner de virus en el cliente o servidor que está escaneando el archivo a medida que se crea.
  2. Windows El bloqueo oportunista tiene la costumbre de arruinar las cosas en los recursos compartidos de red. Recuerdo que es sobre todo un problema con varios clientes de lectura/escritura con bases de datos de archivos planos, pero caching sin duda podría explicar su problema.
  3. Ventanas archivo abrir caché. No estoy seguro de si esto sigue siendo un problema en Win2K o no, pero FileMon te lo diría.

Edit: Si puede capturarlo en el acto desde la máquina servidor, entonces el Identificador de Sysinternal le dirá qué lo tiene abierto.

 0
Author: Mark Brackett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-03 01:00:51