Cómo dividir archivos grandes de manera eficiente

Me gustaría saber cómo puedo dividir un archivo grande sin utilizar demasiados recursos del sistema. Actualmente estoy usando este código:

public static void SplitFile(string inputFile, int chunkSize, string path) { byte[] buffer = new byte[chunkSize]; using (Stream input = File.OpenRead(inputFile)) { int index = 0; while (input.Position < input.Length) { using (Stream output = File.Create(path + "\\" + index)) { int chunkBytesRead = 0; while (chunkBytesRead < chunkSize) { int bytesRead = input.Read(buffer, chunkBytesRead, chunkSize - chunkBytesRead); if (bytesRead == 0) { break; } chunkBytesRead += bytesRead; } output.Write(buffer, 0, chunkBytesRead); } index++; } } } 

La operación demora 52.370 segundos para dividir un archivo de 1.6 GB en archivos de 14 mb. No me preocupa cuánto tiempo dura la operación. Me preocupan más los recursos del sistema utilizados, ya que esta aplicación se implementará en un entorno de alojamiento compartido. Actualmente, esta operación maximiza el uso de HDD IO de mis sistemas al 100%, y ralentiza considerablemente mi sistema. El uso de la CPU es bajo; RAM aumenta un poco, pero parece estar bien.

¿Hay alguna manera de que pueda restringir esta operación de usar demasiados recursos?

Gracias

Parece extraño ensamblar cada archivo de salida en la memoria; Sospecho que deberías ejecutar un búfer interno (tal vez 20k o algo así) y llamar a Write más frecuencia.

En última instancia, si necesita IO, necesita IO. Si desea ser cortés con un entorno de alojamiento compartido, puede agregar pausas deliberadas, tal vez pausas cortas dentro del ciclo interno y una pausa más larga (quizás 1s) en el ciclo externo. Esto no afectará mucho su tiempo general, pero puede ayudar a otros procesos a obtener IO.

Ejemplo de un buffer para el bucle interno:

 public static void SplitFile(string inputFile, int chunkSize, string path) { const int BUFFER_SIZE = 20 * 1024; byte[] buffer = new byte[BUFFER_SIZE]; using (Stream input = File.OpenRead(inputFile)) { int index = 0; while (input.Position < input.Length) { using (Stream output = File.Create(path + "\\" + index)) { int remaining = chunkSize, bytesRead; while (remaining > 0 && (bytesRead = input.Read(buffer, 0, Math.Min(remaining, BUFFER_SIZE))) > 0) { output.Write(buffer, 0, bytesRead); remaining -= bytesRead; } } index++; Thread.Sleep(500); // experimental; perhaps try it } } } 

He modificado un poco el código de la pregunta en caso de que quisieras dividir en fragmentos, asegurándote de que cada fragmento termina en una línea que termina:

  private static void SplitFile(string inputFile, int chunkSize, string path) { byte[] buffer = new byte[chunkSize]; List extraBuffer = new List(); using (Stream input = File.OpenRead(inputFile)) { int index = 0; while (input.Position < input.Length) { using (Stream output = File.Create(path + "\\" + index + ".csv")) { int chunkBytesRead = 0; while (chunkBytesRead < chunkSize) { int bytesRead = input.Read(buffer, chunkBytesRead, chunkSize - chunkBytesRead); if (bytesRead == 0) { break; } chunkBytesRead += bytesRead; } byte extraByte = buffer[chunkSize - 1]; while (extraByte != '\n') { int flag = input.ReadByte(); if (flag == -1) break; extraByte = (byte)flag; extraBuffer.Add(extraByte); } output.Write(buffer, 0, chunkBytesRead); if (extraBuffer.Count > 0) output.Write(extraBuffer.ToArray(), 0, extraBuffer.Count); extraBuffer.Clear(); } index++; } } } 

Actualmente, esta operación maximiza el uso de HDD IO de mis sistemas al 100%.

Esto es lógico: el IO va a ser su factor limitante, y es probable que su sistema tenga el mismo IO malísimo de la mayoría de las computadoras (un disco lento, no un RAID 10 de discos de alto rendimiento).

Puede usar un trozo decente sze (1mb hacia arriba) para reducir las lecturas y escrituras pequeñas, pero al final es TODO lo que PUEDE hacer. O consigue un subsistema de disco más rápido.

Una opción que tienes es acelerar la operación. Si, por ejemplo, recupera el búfer a un tamaño más pequeño (entre 4K y 1MB) y coloca un Thread.Sleep entre las operaciones, usará menos recursos.

Este es un problema para su anfitrión, no para usted. Suponiendo que esto es absolutamente lo que necesita hacer, entonces lo hará de la forma más eficiente posible. Depende de ellos administrar los recursos según la carga, la prioridad, el SLA, etc. de la misma manera que su Hypervisor / VM / OS / App Server / lo que sea.

¡Divida los archivos y use las instalaciones que pagó!