2017-12-20 10 views
2

Ich bin neugierig, warum das folgende Stück Code mit einer System.IO.IOException fehlschlägt, sagen, dass der Prozess nicht zugreifen kann die Datei, weil sie von einem anderen Prozess verwendet wird.Lesen von Dateien in Linq SelectMany() löst System.IO.IOException, wenn ohne ToList ausgeführt()

class Program 
{ 
    static void Main(string[] args) 
    { 
     const string filename = "tmp.txt"; 
     File.AppendAllText(filename, "x"); 
     var output = Enumerable.Range(0, 10).SelectMany(_ => File.ReadAllLines(filename)); 
     File.WriteAllLines(filename, output); 
    } 
} 

Durch einfache ein ToList() am Ende der Linq Pipeline zu werfen, vermeide ich dieses Problem, aber ich habe nicht in der Lage gewesen, um herauszufinden, warum dies der Fall ist.

+0

müssen Sie zuerst eine Datei im Dateisystem erstellen, schreiben Sie Daten darauf und müssen dann von dort lesen. –

+1

'.ToList()' sowie '.ToArray()' * materialisiert * das Ergebnis: Sie haben eine Sammlung im Speicher und keine Datei geöffnet; * Linq * ist faul: Wenn Sie nicht '.ToList()' haben; 'output' startet nur mit' WriteAllLines' (wenn Linq * * lesen muss) und Sie haben einen Konflikt: 'File.WriteAllLines' will ** schreiben ** während' var output = .. 'sollte ** lesen ** –

Antwort

4

Sie sehen die Wirkung von Linq Trägheit und Materialisierung.

Mit .ToList() fügten wir haben die output materialisiert: Linq führt die Abfrage (offen Datei, füllen Sie die Sammlung und schließen der Datei):

// List<T> collection 
var output = Enumerable 
    .Range(0, 10) 
    .SelectMany(_ => File.ReadAllLines(filename)) 
    .ToList(); // <- We want a collection in memory 

Also, wenn es Zeit ist zu schreiben, wir schreiben die Daten aus dem Speicher do Disk

// Writing down the collection 
File.WriteAllLines(filename, output); 

Ohne .ToList() Linq (als faul) tut nichts:

// IEnumerable<T> 
var output = Enumerable 
    .Range(0, 10) 
    .SelectMany(_ => File.ReadAllLines(filename)); // <- No more than a declaration 

Wenn es Zeit

File.WriteAllLines(filename, output); 

Linq findet heraus zu schreiben ist, dass sie die Daten zur Verfügung stellen muss, die sein sollte geschrieben - output und beginnt damit: es versucht, Datei öffnen aber schlägt in diesem Vorgang fehl, da die Datei geöffnet wurde ed mit File.WriteAllLines.

+0

Viel eloquenter als meine verwirrte Terminologie –

+0

Aaaah, natürlich! Danke vielmals! Was mich verwirrte war, dass die IOException aus der File.ReadAllLines geworfen wurde, aber ich denke, es macht Sinn, da die ReadAllLines erst ausgeführt wird, nachdem die WriteAllLines sie zur Eingabe einer Antwort aufgefordert hat. Prost! –

0

Weil Sie gleichzeitig auf die gleiche Datei zu lesen und schreiben versuchen,

ToList() die Ausführung verursacht (Aufzählung) an diesem Punkt passieren, wo die Select ein IEnumerable zurück und wartet, bis seine (aufgezählt) durchgeführt bei File.WriteAllLines(filename, output)

Verwandte Themen