Frage

Ich habe mich anscheinend zu einer schlechten Codierungsgewohnheit gearbeitet. Hier ist ein Beispiel für den Code, den ich geschrieben habe:

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

Ich dachte das, weil die using Klausel explizit angerufen Close() und Dispose() auf der StreamReader dass die FileStream würde auch geschlossen sein.

Der einzige Weg, wie ich das Problem beheben konnte, das ich hatte, war, den obigen Block auf diese zu ändern:

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

Sollte das schließen StreamReader durch Entsorgung im ersten Block schließen auch das zugrunde liegende FileStream? Oder hat ich mich irre?

Bearbeiten

Ich habe mich entschlossen, den tatsächlichen beleidigenden Codeblock zu veröffentlichen, um festzustellen, ob wir dies auf den Grund gehen können. Ich bin jetzt nur neugierig.

Ich dachte, ich hätte ein Problem in der using Klausel, also habe ich alles erweitert, und es kann immer noch nicht jedes Mal kopieren. Ich erstelle die Datei in dieser Methode, daher denke ich, dass etwas anderes ein Handle in der Datei offen hat. Ich habe auch überprüft, dass die Saiten von der zurückgekehrt sind Path.Combine Anrufe sind korrekt.

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);
}
War es hilfreich?

Lösung

Ja, StreamReader.Dispose Schließt den zugrunde liegenden Strom (für alle öffentlichen Möglichkeiten, einen zu schaffen). Es gibt jedoch eine schönere Alternative:

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

Dies hat den zusätzlichen Vorteil, dass es den zugrunde liegenden Stream mit einem Hinweis auf Windows öffnet, auf den Sie nacheinander zugreifen werden.

Hier ist eine Test -App, die die erste Version zeigt, die für mich funktioniert. Ich versuche nicht zu sagen, dass dies ein Beweis für etwas Besonderes ist - aber ich würde gerne wissen, wie gut es für Sie funktioniert.

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

Wenn das funktioniert, deutet es darauf hin, dass es etwas mit dem zu tun hat, was Sie beim Lesen tun ...

Und jetzt ist hier eine verkürzte Version Ihres bearbeiteten Fragencodes - die für mich auch für mich auch auf einer Netzwerkfreigabe funktioniert. Beachten Sie, dass ich mich geändert habe FileMode.Create zu FileMode.CreateNew - wie sonst da könnte Es war immer noch eine App mit einem Handle auf der alten Datei. Geht das für dich?

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

Andere Tipps

Hinweis - Ihre Verwendung von Blöcken müssen nicht in ihren eigenen Blöcken verschachtelt werden - sie können sequentiell sein, wie in:

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

Die Anordnung der Entsorgung ist in diesem Fall immer noch die gleiche wie die verschachtelten Blöcke (dh der StreamReader wird in diesem Fall immer noch vor dem FileStream entsorgen).

Ich würde versuchen zu benutzen FileInfo.Open() und FileInfo.MoveTo() Anstatt von File.Open() und File.Move(). Sie könnten auch versuchen zu verwenden FileInfo.OpenText(). Aber das sind nur Vorschläge.

Gibt es eine Möglichkeit, dass etwas anderes ein Schloss für einen file.txt hat?

Eine einfache Überprüfung von einer lokalen (in die Datei) CMD -Zeile

net files

Möglicherweise gibt Ihnen ein paar Hinweise, wenn etwas anderes ein Schloss hat.

Alternativ können Sie so etwas bekommen wie Filemon Um noch mehr Details zu erhalten und zu überprüfen, ob Ihre App ordnungsgemäß veröffentlicht wird.

Da dies kein Codierungsproblem zu sein scheint, werde ich meinen Syadmin -Hut aufnehmen und ein paar Vorschläge geben.

  1. Virus -Scanner auf dem Client oder Server, der die Datei beim Erstellen scannt.
  2. Fenster Opportunistische Sperren Hat die Angewohnheit, Dinge auf Netzwerkanteile zu vermasseln. Ich erinnere mich, dass es meistens ein Problem mit mehreren Lese-/Schreiben von Clients mit flachen Dateidatenbanken war, aber jedoch zwischengespeichert Könnte sicherlich Ihr Problem erklären.
  3. Fenster Datei öffnen Cache. Ich bin mir nicht sicher, ob dies in Win2K immer noch ein Problem ist oder nicht, aber Filemon würde es Ihnen sagen.

Bearbeiten: Wenn Sie es in der ACT von der Servermaschine fangen können, werden Ihnen das Handle von Sysinternal mitgeteilt, was es offen hat.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top