2016-04-11 2 views
2

Ich habe einen Datenreader-Stream erstellt und ich versuche, die Ergebnisse in eine Datei zu schreiben. Da diese Tabelle möglicherweise Millionen von Datensätzen zurückgeben könnte, wollte ich in mehrere Dateien schreiben, damit ich sie in einem Texteditor ohne die Probleme öffnen konnte, dh. Der Texteditor stürzt ab, weil die Datei zu groß ist. Hier ist ungefähr mein was ich jetzt habe.Schreiben mehrerer Dateien aus SqlDataReader

using (var connection = new SqlConnection(connectionString)) 
using (var stream = new FileStream("directoryLocation", FileMode.Create)) 
{ 
    SqlCommand command = connection.CreateCommand(); 
    command.CommandText = "Select * from tblTemp"; 
    connection.Open(); 

    using(SqlDataReader reader = command.ExecuteReader()) 
    { 
     var tableName = "tblTemp"; 
     var fileName = tableName + ".txt"; 
     var recordCount = 0; 
     var fileCount = 0; 

     using (StreamWriter writer = new StreamWriter(stream.Open())) 
     { 
      while(reader.Read()) 
      { 
       if(recordCount == 500000) 
       { 
        // Right here. Need to figure out how to close old file start new 
        recordCount = 0; 
        writer.Close(); 

        fileName = tableName + "_" + (++fileCount).ToString() + ".txt"; 
        writer = new StreamWriter(fileName); // I know this doesn't work. Just sudo code 
       } 

       recordCount++; 
       writer.WriterLine(recordInfo); // recordInfo is sudo code as well 
      } 
     } 
    } 
} 

Ich will nicht die Verwendung von Schreiber Anweisung in die Leser-Schleife bewegen, denn das würde die Verbindung zur Datei für jeden Datensatz öffnen und schließen. Irgendwelche Ideen, wie ich meine Position im Leser behalten und Dateien nur bei Bedarf öffnen und schließen kann?

+0

Gerade als ich das postete hatte ich eine Idee. Könnte ich den StreamWriter nicht einfach über den Writerblock selbst verwalten? Wie 'StreamWriter writer = new StreamWriter (stream.Open())' dann try finally blocks um die Verbindung zu verwalten. – adam

+0

Warum brauchen Sie sowohl einen FileSteam als auch einen StreamWriter? Einen Stream einfügen.Open() in einem neuen StreamWriter gibt Ihnen zwei Ops gleichzeitig, was zu Problemen beim Schließen und erneuten Öffnen führt. – jdweng

Antwort

2

Sie sind in der Nähe. Sie benötigen keinen separaten FileStream. Es ist in Ordnung, einen neuen StreamWriter in der Mitte der Schleife zu erstellen, solange Sie den vorherigen wie gewünscht entsorgen.

using (var connection = new SqlConnection(connectionString)) 
{ 
    SqlCommand command = connection.CreateCommand(); 
    command.CommandText = "Select * from tblTemp"; 
    connection.Open(); 

    using(SqlDataReader reader = command.ExecuteReader()) 
    { 
     var tableName = "tblTemp"; 
     var fileName = tableName + ".txt"; 
     var recordCount = 0; 
     var fileCount = 0; 

     StreamWriter writer = null; 
     try 
     { 
      while (reader.Read()) 
      { 
       if (writer == null || recordCount == 500000) 
       { 
        recordCount = 0; 

        // Close the previous file if it is open... 
        if (writer != null) 
        { 
         writer.Close(); 
         writer.Dispose(); 
        } 

        fileName = tableName + "_" + (++fileCount).ToString() + ".txt"; 

        // Open the new file... 
        writer = new StreamWriter(fileName); 
       } 

       recordCount++; 
       writer.WriterLine(recordInfo); // recordInfo is sudo code as well 
      } 
     } 
     finally 
     { 
      // Make sure the file gets closed... 
      if (writer != null) 
      { 
       writer.Dispose(); 
      } 
     } 
    } 
} 
+0

Danke, mein Herr. Ich überarbeite gerade meinen Code mit deinen Vorschlägen und ich werde dich wissen lassen, wie es läuft. – adam

0

Ich persönlich würde entkoppeln die Logik, um die Dateinamen der Roll den Code aus einer benutzerdefinierten Überschreibung von Textwriter verwenden. So etwas wie dies völlig ungetestet, Gewinde wahrscheinlich nicht sicher, ineffizient (es wird zur Zeit nur ein Zeichen in einer Zeit schreiben!), Und wahrscheinlich fehlerhaften Code:

public class RollingFileWriter : TextWriter 
{ 
    private readonly string _filenamePrefix; 
    private readonly string _fileNameSuffix; 
    private readonly int _maxRecordCount; 
    private Stream _innerStream; 
    private int _recordCount = 0; 
    private int _fileCounter = 0; 

    public RollingFileWriter(string filenamePrefix, string fileNameSuffix = ".txt", int maxRecordCount = 500000) 
    { 
     _filenamePrefix = filenamePrefix; 
     _fileNameSuffix = fileNameSuffix; 
     _maxRecordCount = maxRecordCount; 

     _innerStream = new FileStream(
      _filenamePrefix + "_" + _fileCounter.ToString() + _fileNameSuffix, 
      FileMode.Create); 
    } 

    public override Encoding Encoding 
    { 
     get { return Encoding.UTF8; } 
    } 

    public override void Write(char value) 
    { 
     _innerStream.Write(Encoding.GetBytes(new[] { value }), 0, 1); 
    } 

    public override void WriteLine(string value) 
    { 
     if (++_recordCount == _maxRecordCount) 
     { 
      SwitchStreams(); 
     } 
     base.WriteLine(value); 
    } 

    private void SwitchStreams() 
    { 
     _innerStream.Close(); 
     _innerStream.Dispose(); 

     _innerStream = new FileStream(
      _filenamePrefix + "_" + (++_fileCounter).ToString() + _fileNameSuffix, 
      FileMode.Create); 
     _recordCount = 0; 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      _innerStream.Dispose(); 
     } 
    } 
} 

Dann können Sie von den äußeren FileStream loszuwerden, und Ersetzen Sie die innere StreamWriter durch die RollingFileWriter, und entfernen Sie alle anderen Logik aus der Schleife.