web-dev-qa-db-fra.com

Est-ce que l'utilisation de la clause fermera ce flux?

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

Je pensais que parce que la clause using _ appelé explicitement appelé Close() et Dispose() sur le StreamReader que le FileStream serait fermé aussi .

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

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 par disposition dans le premier bloc, fermez également le sous-jacent FileStream? Ou, était-ce que je me suis trompé?

Éditer

J'ai décidé de poster le bloc de code délinquant réel pour voir si nous pouvons aller au fond de cela. Je suis juste curieux maintenant.

Je pensais avoir eu un problème dans la clause using, donc j'ai tout élargi, et cela ne peut toujours pas copier, à chaque fois. Je crée le fichier dans cette méthode appel, donc je ne pense pas que rien d'autre ait une poignée ouverte sur le fichier. J'ai également vérifié que les chaînes sont revenues des appels Path.Combine 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);
}
28
scottm

Oui, StreamReader.Dispose ferme le flux sous-jacent (pour toutes les méthodes publiques de la créer une). Cependant, il y a une alternative plus agréable:

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

Cela dispose de l'avantage supplémentaire qu'il ouvre le flux sous-jacent avec une indice à des fenêtres que vous allez y accéder 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 modifié - qui fonctionne à nouveau bien pour moi, même sur une part de réseau. Notez que j'ai changé FileMode.Create à FileMode.CreateNew - Comme autrement, pourrait a 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");
    }
}
39
Jon Skeet

Remarque - Votre utilisation de blocs n'a pas besoin d'être imbriquée 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 ce cas est toujours le même que les blocs imbriqués (c'est-à-dire que le courant de diffusion sera toujours disposé avant la FILESTREAM dans ce cas).

11
Not Sure

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

1
MartinStettner

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

Un simple chèque d'une ligne locale (à la file) cmd

net files

peut bien vous donner des indices si autre chose a une serrure.

Sinon, vous pouvez obtenir quelque chose comme filemon Pour prendre encore plus de détails et vérifier que votre application publie correctement.

0

Comme cela ne semble pas être une question de codage, je vais mettre mon chapeau de Syadmin et offrir quelques suggestions.

  1. Scanner de virus sur le client ou le serveur qui analyse le fichier tel qu'il est créé.
  2. Windows verrouillage opportuniste a l'habitude de baiser des choses sur des actions réseau. Je me souviens qu'il s'agit principalement d'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. Windows Fichier Ouvrir le cache . Je ne sais pas si cela reste un problème dans Win2k ou non, mais le filon vous dirait.

Edit: Si vous pouvez l'attraper dans l'acte à partir de la machine serveur, la poignée de Sysinternal vous indiquera ce qui l'a ouvert.

0
Mark Brackett