Question

J'ai apparemment travaillé dans une mauvaise habitude de codage. Voici un exemple du code que j'ai écrit:

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

J'ai pensé que parce que le using clause explicitement appelée Close() et Dispose() sur le StreamReader que le FileStream serait également fermé.

La seule façon dont je pouvais résoudre le problème que j'avais était de changer le bloc ci-dessus:

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

Devrait fermer le StreamReader en éliminant dans le premier bloc fermer également le sous-jacent FileStream? Ou, me trompe-je?

Éditer

J'ai décidé de publier le bloc de code offensant réel, pour voir si nous pouvons aller au bas de cela. Je suis juste curieux maintenant.

Je pensais que j'avais un problème dans le using Clause, donc j'ai tout étendu, et il ne peut toujours pas copier à chaque fois. Je crée le fichier dans cet appel de méthode, donc je ne pense pas que tout le reste a une poignée ouverte sur le fichier. J'ai également vérifié que les cordes sont revenus du Path.Combine Les appels sont corrects.

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);
}
Était-ce utile?

La solution

Oui, StreamReader.Dispose Ferme le flux sous-jacent (pour toutes les manières publiques de créer une). Cependant, il y a une plus belle alternative:

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

Cela a l'avantage supplémentaire qu'il ouvre le flux sous-jacent avec un indice à Windows que vous y accéderez séquentiellement.

Voici une application de test qui montre la première version qui fonctionne pour moi. Je n'essaie pas de dire que c'est la preuve de quoi que ce soit en particulier - mais j'aimerais savoir à quel point cela fonctionne bien pour vous.

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 cela fonctionne, cela suggère que c'est quelque chose à voir avec ce que vous faites en lisant ...

Et maintenant, voici une version abrégée de votre code de question édité - qui fonctionne encore bien pour moi, même sur un partage de réseau. Notez que j'ai changé FileMode.Create à FileMode.CreateNew - comme autrement là pourrait ont toujours été une application avec une poignée sur l'ancien fichier, potentiellement. Est-ce que ça marche pour toi?

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

Autres conseils

Remarque - Vos blocs d'utilisation n'ont pas besoin d'être imbriqués dans leurs propres blocs - ils peuvent être séquentiels, comme dans:

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

L'ordre d'élimination dans cette affaire est toujours le même que les blocs imbriqués (c'est-à-dire que le lecteur de stream disposera toujours devant le filestream dans cette affaire).

J'essaierais d'utiliser FileInfo.Open() et FileInfo.MoveTo() à la place de File.Open() et File.Move(). Vous pouvez également essayer d'utiliser FileInfo.OpenText(). Mais ce ne sont que des suggestions.

Y a-t-il une possibilité que quelque chose d'autre ait une serrure pour quelque fixe.txt?

Un simple chèque d'une ligne CMD locale (au fichier)

net files

peut bien vous donner quelques indices si quelque chose d'autre a une serrure.

Vous pouvez également obtenir quelque chose comme Filete Pour prendre encore plus de détails et vérifier que votre application se lance correctement.

Comme cela ne semble pas être un problème de codage, je vais mettre mon chapeau syadmin et proposer quelques suggestions.

  1. Scanner de virus sur le client ou le serveur qui scanne le fichier lorsqu'il est créé.
  2. les fenêtres verrouillage opportuniste a l'habitude de baiser les choses sur les partages de réseau. Je me souviens que c'était principalement un problème avec plusieurs clients de lecture / écriture avec des bases de données de fichiers plats, mais mise en cache pourrait certainement expliquer votre problème.
  3. les fenêtres Cache ouverte de fichier. Je ne sais pas si c'est toujours un problème dans Win2K ou non, mais Filemon vous le dirait.

EDIT: Si vous pouvez l'attraper dans l'acte depuis la machine du serveur, la poignée de Sysinternal vous dira ce qu'il a ouvert.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top