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é?
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);
}
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");
}
}
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).
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.
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.
Comme cela ne semble pas être une question de codage, je vais mettre mon chapeau de Syadmin et offrir quelques suggestions.
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.