¿Cómo escribir un búfer grande en un archivo binario en C ++, rápido?

242

Estoy tratando de escribir grandes cantidades de datos en mi SSD (unidad de estado sólido). Y por grandes cantidades me refiero a 80 GB.

Navegué por la web en busca de soluciones, pero lo mejor que se me ocurrió fue esto:

#include <fstream>
const unsigned long long size = 64ULL*1024ULL*1024ULL;
unsigned long long a[size];
int main()
{
    std::fstream myfile;
    myfile = std::fstream("file.binary", std::ios::out | std::ios::binary);
    //Here would be some error handling
    for(int i = 0; i < 32; ++i){
        //Some calculations to fill a[]
        myfile.write((char*)&a,size*sizeof(unsigned long long));
    }
    myfile.close();
}

Compilado con Visual Studio 2010 y optimizaciones completas y ejecutado bajo Windows7, este programa alcanza un máximo de 20 MB / s. Lo que realmente me molesta es que Windows puede copiar archivos de otro SSD a este SSD en algún lugar entre 150 MB / sy 200 MB / s. Entonces al menos 7 veces más rápido. Por eso creo que debería poder ir más rápido.

¿Alguna idea de cómo puedo acelerar mi escritura?

Dominic Hofer
fuente
11
¿Sus resultados de tiempo excluyeron el tiempo que lleva hacer sus cálculos para completar un []?
catchmeifyoutry
77
Realmente he hecho esta tarea antes. Usando simple fwrite()podría obtener alrededor del 80% de las velocidades máximas de escritura. Solo con FILE_FLAG_NO_BUFFERINGalguna vez pude obtener la velocidad máxima.
Mysticial
10
No estoy seguro de que sea justo comparar su escritura de archivos con una copia de SSD a SSD. Bien podría ser que SSD a SSD funcione en un nivel inferior, evitando las bibliotecas de C ++ o utilizando el acceso directo a memoria (DMA). Copiar algo no es lo mismo que escribir valores arbitrarios en un archivo de acceso aleatorio.
Igor F.
44
@IgorF .: Eso es una especulación errónea; Es una comparación perfectamente justa (por lo menos, a favor de la escritura de archivos). Copiar a través de una unidad en Windows es solo lectura y escritura; No pasa nada elegante / complicado / diferente debajo.
user541686
55
@MaximYegorushkin: Enlace o no sucedió. : P
user541686

Respuestas:

233

Esto hizo el trabajo (en el año 2012):

#include <stdio.h>
const unsigned long long size = 8ULL*1024ULL*1024ULL;
unsigned long long a[size];

int main()
{
    FILE* pFile;
    pFile = fopen("file.binary", "wb");
    for (unsigned long long j = 0; j < 1024; ++j){
        //Some calculations to fill a[]
        fwrite(a, 1, size*sizeof(unsigned long long), pFile);
    }
    fclose(pFile);
    return 0;
}

Acabo de cronometrar 8 GB en 36 segundos, que es de unos 220 MB / sy creo que eso maximiza mi SSD. También vale la pena señalar que el código en la pregunta usaba un núcleo 100%, mientras que este código solo usa 2-5%.

Muchas gracias a todos.

Actualización : han pasado 5 años, es 2017 ahora. Los compiladores, el hardware, las bibliotecas y mis requisitos han cambiado. Es por eso que hice algunos cambios en el código e hice algunas medidas nuevas.

Primero el código:

#include <fstream>
#include <chrono>
#include <vector>
#include <cstdint>
#include <numeric>
#include <random>
#include <algorithm>
#include <iostream>
#include <cassert>

std::vector<uint64_t> GenerateData(std::size_t bytes)
{
    assert(bytes % sizeof(uint64_t) == 0);
    std::vector<uint64_t> data(bytes / sizeof(uint64_t));
    std::iota(data.begin(), data.end(), 0);
    std::shuffle(data.begin(), data.end(), std::mt19937{ std::random_device{}() });
    return data;
}

long long option_1(std::size_t bytes)
{
    std::vector<uint64_t> data = GenerateData(bytes);

    auto startTime = std::chrono::high_resolution_clock::now();
    auto myfile = std::fstream("file.binary", std::ios::out | std::ios::binary);
    myfile.write((char*)&data[0], bytes);
    myfile.close();
    auto endTime = std::chrono::high_resolution_clock::now();

    return std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
}

long long option_2(std::size_t bytes)
{
    std::vector<uint64_t> data = GenerateData(bytes);

    auto startTime = std::chrono::high_resolution_clock::now();
    FILE* file = fopen("file.binary", "wb");
    fwrite(&data[0], 1, bytes, file);
    fclose(file);
    auto endTime = std::chrono::high_resolution_clock::now();

    return std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
}

long long option_3(std::size_t bytes)
{
    std::vector<uint64_t> data = GenerateData(bytes);

    std::ios_base::sync_with_stdio(false);
    auto startTime = std::chrono::high_resolution_clock::now();
    auto myfile = std::fstream("file.binary", std::ios::out | std::ios::binary);
    myfile.write((char*)&data[0], bytes);
    myfile.close();
    auto endTime = std::chrono::high_resolution_clock::now();

    return std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
}

int main()
{
    const std::size_t kB = 1024;
    const std::size_t MB = 1024 * kB;
    const std::size_t GB = 1024 * MB;

    for (std::size_t size = 1 * MB; size <= 4 * GB; size *= 2) std::cout << "option1, " << size / MB << "MB: " << option_1(size) << "ms" << std::endl;
    for (std::size_t size = 1 * MB; size <= 4 * GB; size *= 2) std::cout << "option2, " << size / MB << "MB: " << option_2(size) << "ms" << std::endl;
    for (std::size_t size = 1 * MB; size <= 4 * GB; size *= 2) std::cout << "option3, " << size / MB << "MB: " << option_3(size) << "ms" << std::endl;

    return 0;
}

Este código se compila con Visual Studio 2017 y g ++ 7.2.0 (nuevos requisitos). Ejecuté el código con dos configuraciones:

  • Laptop, Core i7, SSD, Ubuntu 16.04, g ++ Versión 7.2.0 con -std = c ++ 11 -march = native -O3
  • Escritorio, Core i7, SSD, Windows 10, Visual Studio 2017 Versión 15.3.1 con / Ox / Ob2 / Oi / Ot / GT / GL / Gy

Lo que dio las siguientes medidas (después de deshacerse de los valores de 1 MB, porque eran valores atípicos obvios): ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí Ambas veces la opción 1 y la opción 3 maximizan mi SSD. No esperaba que esto viera, porque la opción 2 solía ser el código más rápido en mi vieja máquina en ese entonces.

TL; DR : Mis medidas indican que debo usar std::fstreammás FILE.

Dominic Hofer
fuente
8
+1 Sí, esto fue lo primero que intenté. FILE*Es más rápido que las transmisiones. No hubiera esperado tal diferencia ya que "debería" haber estado vinculada a E / S de todos modos.
Mysticial
12
¿Podemos concluir que la E / S de estilo C es (extrañamente) mucho más rápida que las transmisiones de C ++?
SChepurin
22
@SChepurin: Si estás siendo pedante, probablemente no. Si estás siendo práctico, probablemente sí. :)
user541686
10
¿Podría explicar (para un burro C ++ como yo) la diferencia entre los dos enfoques y por qué este funciona mucho más rápido que el original?
Mike Chamberlain
11
¿Prepending ios::sync_with_stdio(false);hace alguna diferencia para el código con stream? Tengo curiosidad por saber la gran diferencia entre usar esta línea y no, pero no tengo el disco lo suficientemente rápido como para comprobar el caso de la esquina. Y si hay alguna diferencia real.
Artur Czajka
24

Pruebe lo siguiente, en orden:

  • Tamaño de tampón más pequeño. Escribir ~ 2 MiB a la vez podría ser un buen comienzo. En mi última computadora portátil, ~ 512 KiB era el punto ideal, pero aún no he probado en mi SSD.

    Nota: He notado que los buffers muy grandes tienden a disminuir el rendimiento. He notado pérdidas de velocidad con el uso de buffers de 16 MiB en lugar de buffers de 512 KiB antes.

  • Use _open(o _topensi desea ser correcto para Windows) para abrir el archivo, luego use _write. Esto probablemente evitará una gran cantidad de almacenamiento en búfer, pero no es seguro.

  • Usando funciones específicas de Windows como CreateFiley WriteFile. Eso evitará cualquier almacenamiento en búfer en la biblioteca estándar.

usuario541686
fuente
Verifique los resultados de referencia publicados en línea. Necesita escrituras de 4 KB con una profundidad de cola de 32 o más, o escrituras de 512 KB o más, para obtener cualquier tipo de rendimiento decente.
Ben Voigt
@BenVoigt: Sí, eso se correlaciona conmigo diciendo que 512 KiB fue el punto ideal para mí. :)
user541686
Si. Desde mi experiencia, los tamaños de buffer más pequeños suelen ser óptimos. La excepción es cuando está usando FILE_FLAG_NO_BUFFERING, en el que los búferes más grandes tienden a ser mejores. Ya que creo que FILE_FLAG_NO_BUFFERINGes más o menos DMA.
Mysticial
22

No veo diferencia entre std :: stream / FILE / device. Entre buffering y no buffering.

También tenga en cuenta:

  • Las unidades SSD "tienden" a disminuir (tasas de transferencia más bajas) a medida que se llenan.
  • Las unidades SSD "tienden" a disminuir (velocidades de transferencia más bajas) a medida que envejecen (debido a bits que no funcionan).

Estoy viendo el código correr en 63 segundos.
Por lo tanto, una velocidad de transferencia de: 260M / s (mi SSD se ve un poco más rápido que el suyo).

64 * 1024 * 1024 * 8 /*sizeof(unsigned long long) */ * 32 /*Chunks*/

= 16G
= 16G/63 = 260M/s

Obtengo un aumento sin moverme a FILE * desde std :: fstream.

#include <stdio.h>

using namespace std;

int main()
{
    
    FILE* stream = fopen("binary", "w");

    for(int loop=0;loop < 32;++loop)
    {
         fwrite(a, sizeof(unsigned long long), size, stream);
    }
    fclose(stream);

}

Por lo tanto, el flujo de C ++ funciona tan rápido como lo permite la biblioteca subyacente.

Pero creo que es injusto comparar el sistema operativo con una aplicación construida sobre el sistema operativo. La aplicación no puede hacer suposiciones (no sabe que las unidades son SSD) y, por lo tanto, utiliza los mecanismos de archivo del sistema operativo para la transferencia.

Si bien el sistema operativo no necesita hacer ninguna suposición. Puede indicar los tipos de unidades involucradas y utilizar la técnica óptima para transferir los datos. En este caso, una transferencia directa de memoria a memoria. Intente escribir un programa que copie 80G de una ubicación en la memoria a otra y vea qué tan rápido es eso.

Editar

Cambié mi código para usar las llamadas de nivel inferior:
es decir, sin almacenamiento en búfer.

#include <fcntl.h>
#include <unistd.h>


const unsigned long long size = 64ULL*1024ULL*1024ULL;
unsigned long long a[size];
int main()
{
    int data = open("test", O_WRONLY | O_CREAT, 0777);
    for(int loop = 0; loop < 32; ++loop)
    {   
        write(data, a, size * sizeof(unsigned long long));
    }   
    close(data);
}

Esto no hizo diferencia.

NOTA : Mi unidad es una unidad SSD. Si tiene una unidad normal, puede ver una diferencia entre las dos técnicas anteriores. Pero como esperaba, el no almacenamiento en búfer y el almacenamiento en búfer (cuando se escriben fragmentos grandes mayores que el tamaño del búfer) no hacen ninguna diferencia.

Edición 2:

¿Has probado el método más rápido de copiar archivos en C ++

int main()
{
    std::ifstream  input("input");
    std::ofstream  output("ouptut");

    output << input.rdbuf();
}
Martin York
fuente
55
No voté en contra, pero el tamaño de tu búfer es demasiado pequeño. Lo hice con el mismo búfer de 512 MB que está utilizando el OP y obtengo 20 MB / s con transmisiones frente a 90 MB / s con FILE*.
Mysticial
También su camino con fwrite (a, sizeof (unsigned long long), size, stream); en lugar de fwrite (a, 1, size * sizeof (unsigned long long), pFile); me da 220 MB / s con trozos de 64 MB por escritura.
Dominic Hofer
2
@Mysticial: Me sorprende que el tamaño del búfer marque la diferencia (aunque te creo). El búfer es útil cuando tiene muchas escrituras pequeñas para que el dispositivo subyacente no se moleste con muchas solicitudes. Pero cuando está escribiendo fragmentos grandes no hay necesidad de un búfer al escribir / leer (en un dispositivo de bloqueo). Como tal, los datos deben pasarse directamente al dispositivo subyacente (evitando así el búfer). Sin embargo, si ve una diferencia, esto lo contradiría y me haría preguntarme por qué la escritura realmente está utilizando un búfer.
Martin York
2
La mejor solución NO es aumentar el tamaño del búfer, sino eliminar el búfer y hacer que la escritura pase los datos directamente al dispositivo subyacente.
Martin York
1
@Mysticial: 1) No hay fragmentos pequeños => Siempre es lo suficientemente grande (en este ejemplo). En este caso, los fragmentos son 512M 2) Esta es una unidad SSD (tanto la mía como la OP), por lo que nada de eso es relevante. He actualizado mi respuesta.
Martin York
13

La mejor solución es implementar una escritura asíncrona con doble búfer.

Mira la línea de tiempo:

------------------------------------------------>
FF|WWWWWWWW|FF|WWWWWWWW|FF|WWWWWWWW|FF|WWWWWWWW|

La 'F' representa el tiempo para llenar el búfer y la 'W' representa el tiempo para escribir el búfer en el disco. Entonces, el problema es perder el tiempo entre escribir buffers para archivar. Sin embargo, al implementar la escritura en un hilo separado, puede comenzar a llenar el siguiente búfer de inmediato de esta manera:

------------------------------------------------> (main thread, fills buffers)
FF|ff______|FF______|ff______|________|
------------------------------------------------> (writer thread)
  |WWWWWWWW|wwwwwwww|WWWWWWWW|wwwwwwww|

F - llenado del 1er búfer
f - llenado del 2o búfer
W - escritura del 1er búfer en el archivo
w - escritura del 2o búfer en el archivo
_ - espere mientras se completa la operación

Este enfoque con intercambios de búfer es muy útil cuando llenar un búfer requiere un cálculo más complejo (por lo tanto, más tiempo). Siempre implemento una clase CSequentialStreamWriter que oculta la escritura asincrónica en el interior, por lo que para el usuario final la interfaz solo tiene funciones de escritura.

Y el tamaño del búfer debe ser un múltiplo del tamaño del clúster de disco. De lo contrario, terminará con un rendimiento deficiente escribiendo un único búfer en 2 grupos de discos adyacentes.

Escribiendo el último búfer.
Cuando llama a la función Escribir por última vez, debe asegurarse de que el búfer actual se esté llenando también debe escribirse en el disco. Por lo tanto, CSequentialStreamWriter debería tener un método separado, digamos Finalizar (descarga de búfer final), que debería escribir en el disco la última porción de datos.

Manejo de errores.
Mientras que el código comienza a llenar el segundo búfer, y el primero se está escribiendo en un hilo separado, pero la escritura falla por alguna razón, el hilo principal debe ser consciente de ese error.

------------------------------------------------> (main thread, fills buffers)
FF|fX|
------------------------------------------------> (writer thread)
__|X|

Supongamos que la interfaz de un CSequentialStreamWriter tiene una función Write que devuelve bool o lanza una excepción, por lo tanto, al tener un error en un hilo separado, debe recordar ese estado, por lo que la próxima vez que llame a Write o Finilize en el hilo principal, el método devolverá Falso o arrojará una excepción. Y realmente no importa en qué punto dejaste de llenar un búfer, incluso si escribiste algunos datos después del error, lo más probable es que el archivo esté dañado e inútil.

HandMadeOX
fuente
3
Realizar E / S es paralelo a los cálculos es una muy buena idea, pero en Windows no debe usar hilos para lograrlo. En su lugar, use "E / S superpuestas", que no bloquea uno de sus hilos durante la llamada de E / S. Significa que apenas tiene que preocuparse por la sincronización de subprocesos (simplemente no acceda a un búfer que tenga una operación de E / S activa usándolo).
Ben Voigt
11

Sugeriría probar el mapeo de archivos . Utilicé mmapen el pasado, en un entorno UNIX, y me impresionó el alto rendimiento que podía lograr

Ralph
fuente
1
@nalply Sigue siendo una solución funcional, eficiente e interesante a tener en cuenta.
Yam Marcovic
stackoverflow.com/a/2895799/220060 sobre las ventajas y desventajas de mmap. Tenga en cuenta especialmente "Para los accesos secuenciales puros al archivo, no siempre es la mejor solución". También stackoverflow.com/questions/726471 , efectivamente dice que en un sistema de 32 bits está limitado a 2 o 3 GB. - Por cierto, no fui yo quien rechazó esa respuesta.
nalply
8

¿Podría usar FILE*en su lugar y medir el rendimiento que ha ganado? Un par de opciones es usar en fwrite/writelugar de fstream:

#include <stdio.h>

int main ()
{
  FILE * pFile;
  char buffer[] = { 'x' , 'y' , 'z' };
  pFile = fopen ( "myfile.bin" , "w+b" );
  fwrite (buffer , 1 , sizeof(buffer) , pFile );
  fclose (pFile);
  return 0;
}

Si decides usarlo write, prueba algo similar:

#include <unistd.h>
#include <fcntl.h>

int main(void)
{
    int filedesc = open("testfile.txt", O_WRONLY | O_APPEND);

    if (filedesc < 0) {
        return -1;
    }

    if (write(filedesc, "This will be output to testfile.txt\n", 36) != 36) {
        write(2, "There was an error writing to testfile.txt\n", 43);
        return -1;
    }

    return 0;
}

También te aconsejaría que lo investigaras memory map. Esa puede ser tu respuesta. Una vez tuve que procesar un archivo de 20GB en otro para almacenarlo en la base de datos, y el archivo no se abría. Entonces, la solución es utilizar el mapa de memoria. Lo hice Pythonsin embargo.

cibertextron
fuente
En realidad, un FILE*equivalente directo del código original que usa el mismo búfer de 512 MB obtiene toda su velocidad. Su búfer actual es demasiado pequeño.
Mysticial
1
@Mysticial Pero eso es solo un ejemplo.
cybertextron
En la mayoría de los sistemas, 2corresponde al error estándar, pero aún se recomienda que lo use en STDERR_FILENOlugar de 2. Otro problema importante es que un posible error que no puede obtener es EINTR para cuando recibe una señal de interrupción, este no es un error real y simplemente debe intentarlo nuevamente.
Peyman
6

Intente usar las llamadas API open () / write () / close () y experimente con el tamaño del búfer de salida. Quiero decir, no pase todo el búfer "muchos-muchos-bytes" a la vez, haga un par de escrituras (es decir, TotalNumBytes / OutBufferSize). OutBufferSize puede ser de 4096 bytes a megabyte.

Otro intento: use WinAPI OpenFile / CreateFile y use este artículo de MSDN para desactivar el almacenamiento en búfer (FILE_FLAG_NO_BUFFERING). Y este artículo de MSDN sobre WriteFile () muestra cómo obtener el tamaño de bloque para que la unidad conozca el tamaño óptimo del búfer.

De todos modos, std :: ofstream es un contenedor y puede haber bloqueo en las operaciones de E / S. Tenga en cuenta que atravesar toda la matriz de N-gigabytes también lleva algún tiempo. Mientras escribe un pequeño búfer, llega al caché y funciona más rápido.

Viktor Latypov
fuente
6

fstreamLos s no son más lentos que los flujos C, per se, pero usan más CPU (especialmente si el almacenamiento en búfer no está configurado correctamente). Cuando una CPU se satura, limita la velocidad de E / S.

Al menos, la implementación de MSVC 2015 copia 1 carácter a la vez en el búfer de salida cuando no se establece un búfer de flujo (ver streambuf::xsputn). Así que asegúrese de establecer un búfer de flujo (> 0) .

Puedo obtener una velocidad de escritura de 1500 MB / s (la velocidad máxima de mi SSD M.2) con el fstreamuso de este código:

#include <iostream>
#include <fstream>
#include <chrono>
#include <memory>
#include <stdio.h>
#ifdef __linux__
#include <unistd.h>
#endif
using namespace std;
using namespace std::chrono;
const size_t sz = 512 * 1024 * 1024;
const int numiter = 20;
const size_t bufsize = 1024 * 1024;
int main(int argc, char**argv)
{
  unique_ptr<char[]> data(new char[sz]);
  unique_ptr<char[]> buf(new char[bufsize]);
  for (size_t p = 0; p < sz; p += 16) {
    memcpy(&data[p], "BINARY.DATA.....", 16);
  }
  unlink("file.binary");
  int64_t total = 0;
  if (argc < 2 || strcmp(argv[1], "fopen") != 0) {
    cout << "fstream mode\n";
    ofstream myfile("file.binary", ios::out | ios::binary);
    if (!myfile) {
      cerr << "open failed\n"; return 1;
    }
    myfile.rdbuf()->pubsetbuf(buf.get(), bufsize); // IMPORTANT
    for (int i = 0; i < numiter; ++i) {
      auto tm1 = high_resolution_clock::now();
      myfile.write(data.get(), sz);
      if (!myfile)
        cerr << "write failed\n";
      auto tm = (duration_cast<milliseconds>(high_resolution_clock::now() - tm1).count());
      cout << tm << " ms\n";
      total += tm;
    }
    myfile.close();
  }
  else {
    cout << "fopen mode\n";
    FILE* pFile = fopen("file.binary", "wb");
    if (!pFile) {
      cerr << "open failed\n"; return 1;
    }
    setvbuf(pFile, buf.get(), _IOFBF, bufsize); // NOT important
    auto tm1 = high_resolution_clock::now();
    for (int i = 0; i < numiter; ++i) {
      auto tm1 = high_resolution_clock::now();
      if (fwrite(data.get(), sz, 1, pFile) != 1)
        cerr << "write failed\n";
      auto tm = (duration_cast<milliseconds>(high_resolution_clock::now() - tm1).count());
      cout << tm << " ms\n";
      total += tm;
    }
    fclose(pFile);
    auto tm2 = high_resolution_clock::now();
  }
  cout << "Total: " << total << " ms, " << (sz*numiter * 1000 / (1024.0 * 1024 * total)) << " MB/s\n";
}

Probé este código en otras plataformas (Ubuntu, FreeBSD) y no noté diferencias de velocidad de E / S, pero sí una diferencia de uso de CPU de aproximadamente 8: 1 ( fstreamusó 8 veces más CPU ). Así que uno puede imaginar, si tuviera un disco más rápido, la fstreamescritura se ralentizaría antes que la stdioversión.

rustyx
fuente
3

Si copia algo del disco A al disco B en el explorador, Windows emplea DMA. Eso significa que para la mayor parte del proceso de copia, la CPU básicamente no hará nada más que decirle al controlador de disco dónde colocar y obtener datos, eliminando un paso completo en la cadena y uno que no está optimizado para mover grandes cantidades de datos, y me refiero al hardware.

Lo que haces involucra mucho a la CPU. Quiero señalarle la parte "Algunos cálculos para llenar una parte []". Lo cual creo que es esencial. Usted genera un [], luego copia de un [] a un búfer de salida (eso es lo que hace fstream :: write), luego genera de nuevo, etc.

¿Qué hacer? Multithreading! (Espero que tengas un procesador multi-core)

  • tenedor.
  • Use un hilo para generar datos []
  • Use el otro para escribir datos desde un [] en el disco
  • Necesitará dos matrices a1 [] y a2 [] y cambiará entre ellas
  • Necesitará algún tipo de sincronización entre sus hilos (semáforos, cola de mensajes, etc.)
  • Utilice funciones de nivel inferior, sin búfer, como la función WriteFile mencionada por Mehrdad
dualed
fuente
2

Intenta usar archivos mapeados en memoria.

qehgt
fuente
@Mehrdad pero ¿por qué? ¿Porque es una solución dependiente de la plataforma?
qehgt
3
No ... es porque para escribir rápidamente archivos secuenciales, necesita escribir grandes cantidades de datos a la vez. (Digamos que los fragmentos de 2-MiB son probablemente un buen punto de partida). Los archivos mapeados en memoria no le permiten controlar la granularidad, por lo que está a merced de lo que el administrador de memoria decida buscar previamente / búfer por usted. En general, nunca los he visto ser tan efectivos como la lectura / escritura normal ReadFiley similares para el acceso secuencial, aunque para el acceso aleatorio pueden ser mejores.
user541686
Pero el sistema operativo utiliza los archivos mapeados en memoria para la paginación, por ejemplo. Creo que es una forma altamente optimizada (en términos de velocidad) de leer / escribir datos.
qehgt
77
@Mysticial: La gente sabe "muchas cosas que simplemente están mal."
Ben Voigt
1
@qehgt: en todo caso, la paginación está mucho más optimizada para el acceso aleatorio que el acceso secuencial. Leer 1 página de datos es mucho más lento que leer 1 megabyte de datos en una sola operación.
user541686
1

Si desea escribir rápidamente en secuencias de archivos, puede hacer que la secuencia de lectura del búfer sea más grande:

wfstream f;
const size_t nBufferSize = 16184;
wchar_t buffer[nBufferSize];
f.rdbuf()->pubsetbuf(buffer, nBufferSize);

Además, cuando se escriben muchos datos en archivos, a veces es más rápido extender lógicamente el tamaño del archivo en lugar de hacerlo físicamente, esto se debe a que al extender lógicamente un archivo, el sistema de archivos no pone a cero el nuevo espacio antes de escribir en él. También es inteligente extender lógicamente el archivo más de lo que realmente necesita para evitar muchas extensiones de archivo. La extensión de archivo lógico es compatible con Windows llamando SetFileValidDatao xfsctlcon XFS_IOC_RESVSP64sistemas XFS.


fuente
0

Estoy compilando mi programa en gcc en GNU / Linux y mingw en win 7 y win xp y funcionó bien

puedes usar mi programa y para crear un archivo de 80 GB simplemente cambia la línea 33 a

makeFile("Text.txt",1024,8192000);

cuando salga del programa, el archivo se destruirá y luego verifique el archivo cuando se esté ejecutando

para tener el programa que desea simplemente cambie el programa

el primero es el programa de Windows y el segundo es para GNU / Linux

http://mustafajf.persiangig.com/Projects/File/WinFile.cpp

http://mustafajf.persiangig.com/Projects/File/File.cpp

Ethaan
fuente