PDA

Visualizza la versione completa : [C++] Scrittura file in rete lentissima con ofstream


Whitecrowsrain
29-12-2017, 16:23
Salve,
ho piccolo problema di prestazioni per quanto riguarda la scrittura di un file attraverso la rete.
Il mio codice legge i byte di un file e poi li scrive su un altro file, una sorta di copia incolla. Fin qui tutto bene, ma le prestazioni calano vistosamente quando il file di destinazione è su un percorso di rete e non riesco a capirne il motivo:



//path del file di destinazione
string destinationFile="//cartella_di_rete/file.dati";
//file di destinazione
ofstream outfile(destinationFile, ios::binary | ios::out | ios::trunc);
//crea il buffer di lettura
mybuffer = new uint8[20480*512];
//cicla per leggere il file diviso in diversi chunk
for (int i = 1; i <= chunk; i++)
{
//funzione che legge il file originale e lo copia nel buffer(in realtà è molto più complessa,
// in quanto si tratta di una funzione di terzi ma non ci interessa in questa sede)
bool ckok= ReadFile( mybuffer, i);
if (ckok)
outfile.write((char*)mybuffer, bufSize);
}

delete(mybuffer);
outfile.close();



cioè si parla di 10Mb/s se il file di destinazione è locale contro 2Mb/s se il file è in rete... una differenza piuttosto sensibile direi che in sistemi più performanti del mio di test si fa sentire ancora di più..

qualcuno di voi ha qualche idea?

shodan
29-12-2017, 16:35
Prova a copiare un file delle stesse dimensioni con il file manager e vedi se hai risultati analoghi.

Whitecrowsrain
29-12-2017, 17:08
Prova a copiare un file delle stesse dimensioni con il file manager e vedi se hai risultati analoghi.

Ho provato a copiarlo tramite quella funzione e poi a fare un semplice copia-incolla, velocità non comparabili proprio..
ma ci sta pure che la funzione sia più lenta del semplice copia incolla, in quanto la funzione di lettura del file va ad estrarre dati da un disco virtuale, ma non è possibile che ci sia un divario se il file di destinazione è in locale piuttosto che in rete!

shodan
29-12-2017, 17:40
Prova a utilizzare dei chunk e un buffer più piccolo (non sotto i 4096 bytes o potrebbe scattare il buffering), per non intasare troppo la rete. Del resto std:: ofstream si limita a usare le API del SysOp per l'IO su file.

Se utilizzi windows puoi utilizzare CopyFile,
https://msdn.microsoft.com/it-it/library/windows/desktop/aa363851(v=vs.85).aspx
se è Linux puoi cercare qualcosa di simile.

Whitecrowsrain
29-12-2017, 18:46
Prova a utilizzare dei chunk e un buffer più piccolo (non sotto i 4096 bytes o potrebbe scattare il buffering), per non intasare troppo la rete. Del resto std:: ofstream si limita a usare le API del SysOp per l'IO su file.

Se utilizzi windows puoi utilizzare CopyFile,
https://msdn.microsoft.com/it-it/library/windows/desktop/aa363851(v=vs.85).aspx
se è Linux puoi cercare qualcosa di simile.

non posso usare CopyFile perché non devo salvare un file vero e proprio ma devo salvare una sequenza di byte ( che estraggo di volta in volta con la funzione di lettura ) che poi va a costituire il file di destinazione!
In pratica ogni ciclo estraggo i settori utilizzati di un disco e li accodo ad un file, che poi mi servirà per il ripristino..
Il problema è quando vado ad accodare questi byte al file di destinazione, che se non è in locale rallenta drasticamente la procedura.. (prima usavo un buffer più piccolo ed era molto peggio, ora uso un buffer "elastico" con un max di 10MB che regolo in base al numero di settori da estrarre del disco..)

shodan
29-12-2017, 19:06
Usa direttamente le API di Windows allora. Più in basso di così non si può andare.


//path del file di destinazione
string destinationFile="\\\\cartella_di_rete\\file.dati";
//file di destinazione

// ofstream outfile(destinationFile, ios::binary | ios::out | ios::trunc);

HANDLE hfile = CreateFile(
destinationFile.c_str(),
(GENERIC_READ | GENERIC_WRITE),
(FILE_SHARE_READ | FILE_SHARE_WRITE),
nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr
);

if (hfile == INVALID_HANDLE_VALUE)
/* Errore */
return;

DWORD wbytes = 0;
//crea il buffer di lettura
mybuffer = new uint8[20480*512];
//cicla per leggere il file diviso in diversi chunk
for (int i = 1; i <= chunk; i++) // perché da 1? E' voluto?
{
//funzione che legge il file originale e lo copia nel buffer(in realtà è molto più complessa,
// in quanto si tratta di una funzione di terzi ma non ci interessa in questa sede)
bool ckok= ReadFile( mybuffer, i);
if (ckok)
WriteFile(hfile, mybuffer, bufSize, &wbytes, nullptr);
}

delete[] mybuffer;
CloseHandle(hfile);

Whitecrowsrain
08-01-2018, 15:09
Usa direttamente le API di Windows allora. Più in basso di così non si può andare.


//path del file di destinazione
string destinationFile="\\\\cartella_di_rete\\file.dati";
//file di destinazione

// ofstream outfile(destinationFile, ios::binary | ios::out | ios::trunc);

HANDLE hfile = CreateFile(
destinationFile.c_str(),
(GENERIC_READ | GENERIC_WRITE),
(FILE_SHARE_READ | FILE_SHARE_WRITE),
nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr
);

if (hfile == INVALID_HANDLE_VALUE)
/* Errore */
return;

DWORD wbytes = 0;
//crea il buffer di lettura
mybuffer = new uint8[20480*512];
//cicla per leggere il file diviso in diversi chunk
for (int i = 1; i <= chunk; i++) // perché da 1? E' voluto?
{
//funzione che legge il file originale e lo copia nel buffer(in realtà è molto più complessa,
// in quanto si tratta di una funzione di terzi ma non ci interessa in questa sede)
bool ckok= ReadFile( mybuffer, i);
if (ckok)
WriteFile(hfile, mybuffer, bufSize, &wbytes, nullptr);
}

delete[] mybuffer;
CloseHandle(hfile);




ho provato ed in effetti per quanto riguarda il trasferimento via rete (mentre su una cartella locale è invariato) è quasi due volte più veloce!!
Grazie

Loading