Pregunta

He aparentemente mismo trabajé en un mal hábito de codificación. Este es 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 la cláusula using explícitamente llama Close() y Dispose() en el que el StreamReader FileStream estaría cerrado también.

La única manera de que pudiera solucionar el problema que estaba teniendo era cambiando el bloque anterior para esto:

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

En caso de cierre de la StreamReader disponiendo en el primer bloque también cerrar la FileStream subyacente? O bien, estaba yo equivocado?

Editar

he decidido publicar el bloque ofensivo real de código, para ver si podemos llegar al fondo de esto. Tengo curiosidad ahora.

pensé que tenía un problema en la cláusula using, así que todo lo que fuera ampliado, y todavía no puedo copiar, cada vez. Creo el archivo de esta llamada a un método, por lo que no creo que nada más tiene un identificador abierto en el archivo. También he verificado que las cadenas devueltas de las llamadas Path.Combine son correctos.

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);
}
¿Fue útil?

Solución

Sí, StreamReader.Dispose cierra la secuencia subyacente (para todas las vías públicas de la creación de uno). Sin embargo, hay una alternativa mejor:

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

Esto tiene la ventaja añadida de que se abre la secuencia subyacente con un toque de Windows que se va a acceder de forma secuencial.

Aquí hay una aplicación de prueba que muestra la primera versión de trabajo para mí. No estoy tratando de decir que es prueba de nada en particular, -., Pero me gustaría saber qué tan bien 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 funciona, se sugiere que se trata de algo que ver con lo que se hace durante la lectura ...

Y ahora aquí está una versión abreviada de su código de pregunta editado - que a su vez funciona bien para mí, incluso en un recurso compartido de red. Tenga en cuenta que he cambiado FileMode.Create a FileMode.CreateNew - pues de otro modo podría han sido todavía una aplicación con una manija en el archivo antiguo, potencialmente. ¿Esto funciona para usted?

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

Otros consejos

Nota - los que utilizan bloques no necesitan ser anidado en sus propios bloques - que puede ser secuencial, como en:

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

El orden de disposición en este caso sigue siendo el mismo que los bloques anidados (es decir, el StreamReader todavía disponer antes de la FileStream en este caso).

Me gustaría tratar de utilizar FileInfo.Open() y FileInfo.MoveTo() en lugar de File.Open() y File.Move(). También puede probar a usar FileInfo.OpenText(). Pero estos son sólo sugerencias.

¿Hay alguna posibilidad de que algo más tiene un bloqueo para Unarchivo.txt?

Una simple comprobación de un local (en el fichero) de la línea cmd

net files

bien puede darle algunas pistas si todo lo demás tiene una cerradura.

Como alternativa se puede obtener algo así como FileMon tomar aún más detalles, y comprobar que su aplicación va a lanzar correctamente.

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

  1. Escáner de virus en el cliente o servidor que está escaneando el archivo como se cree.
  2. oportunista bloqueo tiene la costumbre de arruinar las cosas en unidades de red. Recuerdo que siendo sobre todo un problema con varios clientes de lectura / escritura con modelo de tabla, pero almacenamiento en caché sin duda podría explicar su problema.
  3. archivo de caché abierta . No estoy seguro si esto es todavía un problema en Win2K o no, pero FileMon le diría.

Editar: Si se puede tomar en el acto de la máquina servidor, a continuación, la manija de Sysinternal le dirá lo que tiene abierto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top