Scrittura di più file da SqlDataReader

Ho creato un stream di lettore di dati e sto provando a scrivere i risultati su un file. Poiché questa tabella potrebbe potenzialmente restituire milioni di record, volevo scrivere su più file in modo da poterli aprire in un editor di testo senza problemi, ad es. l’editor di testo si arresta in modo anomalo perché il file è troppo grande. Qui è più o meno il mio quello che ho adesso.

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 } } } } 

Non voglio spostare l’istruzione using writer nel ciclo di lettura perché ciò aprirebbe e chiuderebbe la connessione al file per ogni record. Qualche idea su come mantenere la mia posizione nel lettore e aprire e chiudere i file solo quando necessario?

Sei vicino. Non hai bisogno del FileStream separato. Va bene creare un nuovo StreamWriter nel mezzo del loop, purché si disponga di quello precedente, se necessario.

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

Personalmente, eliminerei la logica di far uscire i nomi dei file dal codice usando una sovrascrittura personalizzata di TextWriter. Qualcosa di simile completamente non testato, probabilmente non thread-safe, inefficiente (attualmente scriverà un personaggio alla volta!), E probabilmente un codice bug:

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

Quindi puoi eliminare FileStream esterno e sostituire StreamWriter interno con RollingFileWriter e rimuovere tutta l’altra logica dal loop.