Leggi il file in memoria, passa in rassegna i dati, quindi scrivi il file

Sto cercando di porre una domanda simile a questo post: C: leggi il file binario in memoria, modifica il buffer, scrivi il buffer nel file ma le risposte non mi aiutano (sono nuovo al c ++ quindi non ho potuto capire tutto di esso)

Come faccio ad avere un ciclo per accedere ai dati in memoria e passare linea per linea in modo che possa scriverlo su un file in un formato diverso?

Questo è quello che ho:

#include  #include  #include  #include  #include  #include  #include  #include  #include  #include  using namespace std; int main() { char* buffer; char linearray[250]; int lineposition; double filesize; string linedata; string a; //obtain the file FILE *inputfile; inputfile = fopen("S050508-v3.txt", "r"); //find the filesize fseek(inputfile, 0, SEEK_END); filesize = ftell(inputfile); rewind(inputfile); //load the file into memory buffer = (char*) malloc (sizeof(char)*filesize); //allocate mem fread (buffer,filesize,1,inputfile); //read the file to the memory fclose(inputfile); //Check to see if file is correct in Memory cout.write(buffer,filesize); free(buffer); } 

Apprezzo qualsiasi aiuto!

Modifica (maggiori informazioni sui dati):

I miei dati sono file diversi che variano tra 5 e 10 GB. Ci sono circa 300 milioni di righe di dati. Ogni linea sembra

M359

T359 3520 359

M400

A3592 zng 392

Dove il primo elemento è un carattere, e gli elementi rimanenti potrebbero essere numeri o caratteri. Sto provando a leggere questo in memoria poiché sarà molto più veloce scorrere di riga in volta, che leggere una riga, elaborare e quindi scrivere. Sto compilando in linux a 64 bit. Fammi sapere se ho bisogno di chiarire ulteriormente. Grazie ancora.

Modifica 2 Sto usando un’istruzione switch per elaborare ogni riga, dove il primo carattere di ogni riga determina come formattare il resto della linea. Ad esempio, “M” significa millisecondo e inserisco i seguenti tre numeri in una struttura. Ogni linea ha un primo carattere diverso a cui devo fare qualcosa di diverso.

Quindi perdonatemi il potenziale palesemente ovvio, ma se volete elaborare questa linea per linea, allora …

 #include  #include  #include  using namespace std; int main(int argc, char *argv[]) { // read lines one at a time ifstream inf("S050508-v3.txt"); string line; while (getline(inf, line)) { // ... process line ... } inf.close(); return 0; } 

E basta riempire il corpo del ciclo while? Forse non vedo il vero problema (una foresta per gli alberi è un po ‘cosa).

MODIFICARE

L’OP è in linea con l’uso di uno streambuf personalizzato che potrebbe non essere necessariamente la cosa più portabile al mondo, ma è più interessato a evitare di capovolgere back e forh tra i file di input e di output. Con abbastanza RAM, questo dovrebbe fare il trucco.

 #include  #include  #include  #include  using namespace std; struct membuf : public std::streambuf { membuf(size_t len) : streambuf() , len(len) , src(new char[ len ] ) { setg(src.get(), src.get(), src.get() + len); } // direct buffer access for file load. char * get() { return src.get(); }; size_t size() const { return len; }; private: std::unique_ptr src; size_t len; }; int main(int argc, char *argv[]) { // open file in binary, retrieve length-by-end-seek ifstream inf(argv[1], ios::in|ios::binary); inf.seekg(0,inf.end); size_t len = inf.tellg(); inf.seekg(0, inf.beg); // allocate a steam buffer with an internal block // large enough to hold the entire file. membuf mb(len+1); // use our membuf buffer for our file read-op. inf.read(mb.get(), len); mb.get()[len] = 0; // use iss for your nefarious purposes std::istream iss(&mb); std::string s; while (iss >> s) cout << s << endl; return EXIT_SUCCESS; } 

Dovresti esaminare fgets e scanf, in cui puoi estrarre parti di dati corrispondenti in modo che sia più facile da manipolare, assumendo che sia quello che vuoi fare. Qualcosa di simile potrebbe sembrare:

 FILE *input = fopen("file.txt", "r"); FILE *output = fopen("out.txt","w"); int bufferSize = 64; char buffer[bufferSize]; while(fgets(buffer,bufferSize,input) != EOF){ char data[16]; sscanf(buffer,"regex",data); //manipulate data fprintf(output,"%s",data); } fclose(output); fclose(input); 

Questo sarebbe più del modo C per farlo, C ++ gestisce le cose in modo un po ‘più eloquente usando un istream: http://www.cplusplus.com/reference/istream/istream/

Se dovessi farlo, probabilmente userei codice come questo:

 std::ifstream in("S050508-v3.txt"); std::istringstream buffer; buffer << in.rdbuf(); std::string data = buffer.str(); if (check_for_good_data(data)) std::cout << data; 

Questo presuppone che tu abbia veramente bisogno dell'intero contenuto del file di input in memoria per determinare se debba essere copiato in output o meno. Se (ad esempio) puoi guardare i dati un byte alla volta e determinare se quel byte dovrebbe essere copiato senza guardare gli altri, potresti fare qualcosa di più:

 std::ifstream in(...); std::copy_if(std::istreambuf_iterator(in), std::istreambuf_iterator(), std::ostream_iterator(std::cout, ""), is_good_char); 

... dove is_good_char è una funzione che restituisce un bool dice se quel char deve essere incluso nell'output o meno.

Modifica: la dimensione dei file con cui si ha a che fare esclude per lo più la prima possibilità che ho dato sopra. Hai anche ragione nel dire che leggere e scrivere grandi porzioni di dati quasi sicuramente migliorerà la velocità di lavoro su una riga alla volta.