Problem mit ReadFile()
-
lemon03 schrieb:
Ich denke, die Antwort darauf würde zu weit führen und ich kann mir auch nicht recht vorstellen, das es für die Fehlersuche von Belang wäre. Sorry.
Dann darfst du uns aber wenigstens deine Makroorgie und die Verwendung von new[] erklären. Insbesondere für letzteres kann es nun wirklich keine Gründe geben.
Zu deinem Problem: Nun, es steht ja auch nichts drin an der Stelle in der Datei. Der Dateizeiger zeigt nach dem Schreiben hinter das geschriebene. Da du die Datei neu erstellst, kann an der Stelle logischerweise nichts mehr sein.
edit: zu langsam.
-
Nun ... :
Ich bin mit meinem C++ noch recht am Anfang und wollte mal versuchen einen kleinen Festplattenbenchmark zu schreiben. Angefangen habe ich mit put/get aber dort kamen unrealistische Werte raus und mir wurde gesagt, es sei reichlich ineffizient und ich solle CreateFile() und WriteFile/ReadFile nehmen oder zumindest write/read.
Mit write/read kamen schon etwas realistischere Werte raus, nur beim Lesen kam ich immer auf über 1 GB/s. Mir wurde gesagt, der Grund wäre das Caching des OS und ich solle doch wirklich mal CreateFile nehmen, vielleicht auch mit dem Flag FILE_FLAG_NO_BUFFERING.
Ich muss aber gestehen, das mir die WinAPI doch etwas schwer fällt, weshalb ich hier aufgeschlagen bin.
Was ich möchte, ist ein File gewählter Größe schreiben, was dann wieder eingelesen wird, dann noch ein Kopiervorgang aus lesen und schreiben.
Der Vorgang wird gemessen und wird in MB/s ausgegeben.
char *filebuffer habe ich von meinen write/read Versuchen übernommen und da bei WriteFile() auch alles in Ordnung war, dachte ich, das das dann auch nicht falsch wäre.
EDIT:
Um zu zeigen, was ich bisher versucht habe, mein Versuch mit write/read:
#include <iostream> //#include <string> #include <fstream> #include <cmath> #include <windows.h> #include <cstdio> //für remove() using namespace std; const int MB = pow(2, 20); //MegaByte const int GB = pow(2, 30); //Gigabyte /* int prozent(int i, int filesize){ int value = (i * 100) / filesize; return value; } */ bool pruefePartition(char partChar){ string testfile = ":/hdbench_test"; testfile = partChar + testfile; ofstream file(testfile.c_str()); if (!file){ cout << "Fehler bei " << partChar << ":" << endl; return false; } file.close(); remove(testfile.c_str()); return true; } void schreibenFile(string bchfile, int filesize, char *filebuffer){ ofstream file(bchfile.c_str(), ofstream::binary); file.write(filebuffer, filesize); file.close(); } void lesenFile(string bchfile, int filesize, char *filebuffer){ ifstream file(bchfile.c_str(), ifstream::binary); file.read(filebuffer, filesize); file.close(); } void kopierenFile(string bchfile, int filesize, char *filebuffer){ string bchfile_copy = bchfile + "_copy"; ifstream file(bchfile.c_str(), ifstream::binary); ofstream file_copy(bchfile_copy.c_str(), ofstream::binary); file.read(filebuffer, filesize); file_copy.write(filebuffer, filesize); file_copy.close(); file.close(); } int main(){ char partChar; //Buchstabe der Partition do{ do{ cin.sync(); cout << "Partition angeben (nur den Buchstaben): "; partChar = cin.get(); }while ((partChar < 'A' || partChar > 'z') && (!(partChar > 'Z' && partChar < 'a'))); }while (!pruefePartition(partChar)); cout << endl; string bchfile = ":/hdbench_file"; //Name des Benchfile bchfile = partChar + bchfile; int filesize = GB; //Größe des Benchfile char *filebuffer = new char [filesize]; //Speicher für Benchfile reservieren LONGLONG frequency, curentCount, lastCount; //Variablen für Zeitmessung QueryPerformanceFrequency((LARGE_INTEGER*) & frequency); //Performance Counter holen double time_sec; //Zeit in Sekunden cout << "messe Schreiben ..." << endl; QueryPerformanceCounter((LARGE_INTEGER*) & curentCount); //1. Messung schreibenFile(bchfile, filesize, filebuffer); QueryPerformanceCounter((LARGE_INTEGER*) & lastCount); //2. Messung time_sec = (((double)(lastCount - curentCount)) / ((double)frequency)); //Zeit in Sekunden ist Differenz von Messung 2 und Messung 1 double time_write = time_sec; cout << "messe Lesen ..." << endl; QueryPerformanceCounter((LARGE_INTEGER*) & curentCount); //1. Messung lesenFile(bchfile, filesize, filebuffer); QueryPerformanceCounter((LARGE_INTEGER*) & lastCount); //2. Messung time_sec = (((double)(lastCount - curentCount)) / ((double)frequency)); //Zeit in Sekunden ist Differenz von Messung 2 und Messung 1 double time_read = time_sec; cout << "messe Kopieren ..." << endl; QueryPerformanceCounter((LARGE_INTEGER*) & curentCount); //1. Messung kopierenFile(bchfile, filesize, filebuffer); QueryPerformanceCounter((LARGE_INTEGER*) & lastCount); //2. Messung time_sec = (((double)(lastCount - curentCount)) / ((double)frequency)); //Zeit in Sekunden ist Differenz von Messung 2 und Messung 1 double time_copy = time_sec; remove(bchfile.c_str()); remove((bchfile + "_copy").c_str()); delete filebuffer; int size_MB = filesize / MB; cout << endl; cout << size_MB << " MB geschrieben in Sekunden: " << time_write; cout.width(12); cout << "MB/s: " << size_MB / time_write << endl; cout << size_MB << " MB gelesen in Sekunden: " << time_read; cout.width(12); cout << "MB/s: " << size_MB / time_read << endl; cout << size_MB << " MB kopiert in Sekunden: " << time_copy; cout.width(12); cout << "MB/s: " << size_MB / time_copy << endl; }und mein aktueller Versuch:
#include <iostream> //#include <string> //#include <fstream> #include <cmath> #include <windows.h> #include <cstdio> //für remove() using namespace std; const int MB = pow(2, 20); //MegaByte //const int GB = pow(2, 30); //Gigabyte /* int prozent(int i, int filesize){ int value = (i * 100) / filesize; return value; } */ /* void schreibenFile(HANDLE benchFile, int filesize, char *filebuffer_out) { DWORD bytesWritten = 0; WriteFile(benchFile, filebuffer_out, filesize, &bytesWritten, NULL); //CloseHandle(benchFile); } */ /* void lesenFile(HANDLE benchFile, int filesize, char *filebuffer_in) { DWORD bytesRead = 0; ReadFile(benchFile, filebuffer_in, filesize, &bytesRead, NULL); cout << bytesRead << endl; } */ /* void kopierenFile(string bchfile, int filesize, char *filebuffer) { string bchfile_copy = bchfile + "_copy"; ifstream file(bchfile.c_str(), ifstream::binary); ofstream file_copy(bchfile_copy.c_str(), ofstream::binary); file.read(filebuffer, filesize); file_copy.write(filebuffer, filesize); file_copy.close(); file.close(); } */ int main(){ string filename_proto = ":/hdbench_file"; //Name des Benchfile string filename; char partChar; //Buchstabe der Partition bool partChar_true; //Partitionsbuchstabe gültig? HANDLE benchFile; do{ do{ cin.sync(); cout << "Partition angeben (nur den Buchstaben): "; partChar = cin.get(); }while ((partChar < 'A' || partChar > 'z') && (!(partChar > 'Z' && partChar < 'a'))); filename = partChar + filename_proto; benchFile = CreateFile(filename.c_str(), //Benchfile anlegen GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, // | FILE_FLAG_NO_BUFFERING, NULL); if (benchFile == INVALID_HANDLE_VALUE){ cout << "Fehler bei " << partChar << ":" << endl; partChar_true = false; }else{ partChar_true = true; } }while (!partChar_true); cout << endl; int filesize = 100 * MB; //Größe des Benchfile char *filebuffer = new char [filesize]; //Speicher für Benchfile reservieren LONGLONG frequency, curentCount, lastCount; //Variablen für Zeitmessung QueryPerformanceFrequency((LARGE_INTEGER*) & frequency); //Performance Counter holen double time_sec; //Zeit in Sekunden cout << "messe Schreiben ..." << endl; //char *filebuffer_out = new char [filesize]; //Speicher für Benchfile reservieren DWORD bytesWritten = 0; QueryPerformanceCounter((LARGE_INTEGER*) & curentCount); //1. Messun WriteFile(benchFile, filebuffer, filesize, &bytesWritten, NULL); cout << bytesWritten << endl; QueryPerformanceCounter((LARGE_INTEGER*) & lastCount); //2. Messung time_sec = (((double)(lastCount - curentCount)) / ((double)frequency)); //Zeit in Sekunden ist Differenz von Messung 2 und Messung 1 double time_write = time_sec; cout << "messe Lesen ..." << endl; //char *filebuffer_in = new char [filesize]; //Speicher für Benchfile reservieren DWORD bytesRead = 0; QueryPerformanceCounter((LARGE_INTEGER*) & curentCount); //1. Messung ReadFile(benchFile, filebuffer, filesize, &bytesRead, NULL); cout << bytesRead << endl; QueryPerformanceCounter((LARGE_INTEGER*) & lastCount); //2. Messung time_sec = (((double)(lastCount - curentCount)) / ((double)frequency)); //Zeit in Sekunden ist Differenz von Messung 2 und Messung 1 double time_read = time_sec; /* cout << "messe Kopieren ..." << endl; string filename_copy = filename +"_copy"; HANDLE benchFile_copy = CreateFile(filename_copy.c_str(), //Benchfile anlegen GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); QueryPerformanceCounter((LARGE_INTEGER*) & curentCount); //1. Messung kopierenFile(benchFile, benchfile_copy, filesize, filebuffer); QueryPerformanceCounter((LARGE_INTEGER*) & lastCount); //2. Messung time_sec = (((double)(lastCount - curentCount)) / ((double)frequency)); //Zeit in Sekunden ist Differenz von Messung 2 und Messung 1 double time_copy = time_sec; */ CloseHandle(benchFile); //remove(filename.c_str()); //remove((bchfile + "_copy").c_str()); //delete filebuffer; int size_MB = filesize / MB; cout << endl; cout << size_MB << " MB geschrieben in Sekunden: " << time_write; cout.width(12); cout << "MB/s: " << size_MB / time_write << endl; cout << size_MB << " MB gelesen in Sekunden: " << time_read; cout.width(12); cout << "MB/s: " << size_MB / time_read << endl; //cout << size_MB << " MB kopiert in Sekunden: " << time_copy; cout.width(12); cout << "MB/s: " << size_MB / time_copy << endl; }
-
Kurz gesagt: Du versuchst da gerade unfreiwillig, einen Benchmark für den Arbeitsspeicher zu schreiben.
-
Ja, das habe ich zumindest beim Lesen auch festgestellt. Beim Schreiben kommen so Werte um 120 MB/s raus, die auch tatsächliche Benchmarks anzeigen.
Und ich hatte halt gehofft, mit CreateFile und ReadFile könnte ich das umgehen.
-
SeppJ schrieb:
Kurz gesagt: Du versuchst da gerade unfreiwillig, einen Benchmark für den Arbeitsspeicher zu schreiben.
Ich hab mich auch mal dran versucht... Meiner Meinung nach sollte das ja der richtige Weg sein:
/*timer.hpp*/ #include "windows.h" #include <cassert> #include <stdexcept> struct large_integer_t { typedef __int64 integral_type; operator float() const { return static_cast<float>( static_cast<integral_type>(*this) ); } operator integral_type() const { return data.QuadPart; } operator integral_type() { return data.QuadPart; } large_integer_t() : data(LARGE_INTEGER()) {} large_integer_t(const LARGE_INTEGER& data) : data(data) {} large_integer_t& operator-= (const large_integer_t& other) { data.QuadPart -= other.data.QuadPart; return *this; } private: LARGE_INTEGER data; }; large_integer_t operator- (const large_integer_t& lhs, const large_integer_t& rhs) { large_integer_t tmp(lhs); tmp -= rhs; return tmp; } class timer_t { public: typedef float second_t; timer_t() : begin(get_timestamp()) #if !defined (NDEBUG) , stopped(false) #endif //#if !defined (_NDEBUG) { end = begin; } void stop() { #if !defined (NDEBUG) stopped = true; #endif //#if !defined (_NDEBUG) end = get_timestamp(); } second_t get_seconds() const { assert(stopped); return (end-begin)/static_cast<second_t>(get_frequency()); } private: #if !defined (NDEBUG) bool stopped; #endif //#if !defined (_NDEBUG) static large_integer_t get_frequency() { LARGE_INTEGER ret_val; BOOL succeed = QueryPerformanceFrequency(&ret_val); if(!succeed) throw std::runtime_error("calling QueryPerformanceFrequency failed"); return ret_val; } static large_integer_t get_timestamp() { LARGE_INTEGER ret_val; BOOL succeed = QueryPerformanceCounter(&ret_val); if(!succeed) throw std::runtime_error("calling QueryPerformanceCounter failed"); return ret_val; } large_integer_t begin; large_integer_t end; };/*file_op.hpp*/ #include "windows.h" #include <stdexcept> class file_t { public: bool is_open() const { return fd != INVALID_HANDLE_VALUE; } bool bad() const { return !is_open() || op_failed; } bool good() const { return !bad(); } void write(char* const first, std::size_t length) { if(bad()) return; DWORD length_wrote; BOOL succeeds = WriteFile(fd, first, static_cast<DWORD>(length), &length_wrote, NULL); op_failed = !succeeds || (static_cast<std::size_t>(length_wrote) != length); } void read(char* first, std::size_t length) { if(bad()) return; DWORD length_read; BOOL succeeds = ReadFile(fd, first, static_cast<DWORD>(length), &length_read, NULL); op_failed = !succeeds || (static_cast<std::size_t>(length_read) != length); } static file_t create(const char* filename) { HANDLE hwnd = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); return file_t(hwnd); } static file_t open(const char* filename) { HANDLE hwnd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); return file_t(hwnd); } static void close(file_t& to_close) { if( !to_close.is_open() ) return; CloseHandle(to_close.fd); to_close.fd = INVALID_HANDLE_VALUE; } private: explicit file_t(HANDLE fd) : fd(fd), op_failed(false) {} HANDLE fd; bool op_failed; }; void delete_file(const char* filename) { BOOL succeed = DeleteFile(filename); if(!succeed) throw std::runtime_error("cannot delete file"); }/*main.cpp*/ #include "timer.hpp" #include "file_op.hpp" template <class T, std::size_t n> std::size_t size_of(const T(&)[n]) { return n; } void do_and_print(const char* filename, std::size_t size_in_mb); #include <iostream> int main() { const char* filenames[] = { "C:/tmp.txt", "E:/tmp.txt", "L:/tmp.txt", "H:/tmp.txt" }; std::size_t megabyte_count; std::cout << "wie viele MB sollen jeweils gelesen/geschrieben werden?" << std::endl; std::cin >> megabyte_count; for(std::size_t i = 0; i != size_of(filenames); ++i) { std::cout << filenames[i] << std::endl; do_and_print(filenames[i], megabyte_count); } #if 0 std::cout << "Taste..." << std::endl; std::cin.ignore(); std::cin.get(); #endif } #include <algorithm> #include <iomanip> #include <vector> void do_and_print(const char* filename, std::size_t size_in_mb) { if(size_in_mb == 0) return; std::ios_base::fmtflags flag_backup = std::cout.flags(); std::cout << std::setprecision(3) << std::fixed; const std::size_t MB = 1024 * 1024; const std::size_t buffer = size_in_mb * MB; bool created_file = false; std::vector<char> to_write(buffer, '1'); { file_t file = file_t::create(filename); created_file = file.is_open(); timer_t time; file.write(&to_write[0], to_write.size()); time.stop(); if(file.bad()) std::cout << "schreiben fehlgeschlagen" << std::endl; else std::cout << "schreiben (" << size_in_mb << " MB): " << time.get_seconds() << "-> " << size_in_mb/time.get_seconds() << " MBps" << std::endl; file_t::close(file); } std::vector<char> to_read(buffer, '0'); if(created_file) { file_t file = file_t::open(filename); timer_t time; file.read(&to_read[0], to_read.size()); time.stop(); if(file.bad()) std::cout << "lesen fehlgeschlagen" << std::endl; else std::cout << " lesen (" << size_in_mb << " MB): " << time.get_seconds() << "-> " << size_in_mb/time.get_seconds() << " MBps" << std::endl; file_t::close(file); } if(to_write != to_read) std::cout << "kaputt ;)" << std::endl; if(created_file) delete_file(filename); std::cout.flags(flag_backup); }wie viele MB sollen jeweils gelesen/geschrieben werden? C:/tmp.txt schreiben (5 MB): 0.162-> 30.818 MBps lesen (5 MB): 0.228-> 21.895 MBps E:/tmp.txt schreiben (5 MB): 0.180-> 27.835 MBps lesen (5 MB): 0.003-> 1495.359 MBps L:/tmp.txt schreiben (5 MB): 0.149-> 33.455 MBps lesen (5 MB): 0.054-> 92.113 MBps H:/tmp.txt schreiben (5 MB): 1.983-> 2.521 MBps lesen (5 MB): 0.253-> 19.797 MBpswie viele MB sollen jeweils gelesen/geschrieben werden? C:/tmp.txt schreiben (50 MB): 1.621-> 30.850 MBps lesen (50 MB): 1.769-> 28.257 MBps E:/tmp.txt schreiben (50 MB): 1.397-> 35.779 MBps lesen (50 MB): 0.035-> 1416.357 MBps L:/tmp.txt schreiben (50 MB): 1.222-> 40.904 MBps lesen (50 MB): 0.383-> 130.452 MBps H:/tmp.txt schreiben (50 MB): 5.537-> 9.030 MBps lesen (50 MB): 2.360-> 21.189 MBpswie viele MB sollen jeweils gelesen/geschrieben werden? C:/tmp.txt schreiben (200 MB): 6.472-> 30.902 MBps lesen (200 MB): 6.657-> 30.043 MBps E:/tmp.txt schreiben (200 MB): 6.053-> 33.041 MBps lesen (200 MB): 0.211-> 949.562 MBps L:/tmp.txt schreiben (200 MB): 4.585-> 43.617 MBps lesen (200 MB): 1.978-> 101.106 MBps H:/tmp.txt schreiben (200 MB): 26.159-> 7.645 MBps lesen (200 MB): 9.288-> 21.534 MBpsC+E sind Partitionen auf ner uralten IDE Platte. Bei E ist die Komprimierung aktiviert, deshalb die utopischen Lese-Werte^^
L ist nen RAID5 über 5 SATA Platten, da sollte aber einiges an Geschwindigkeit durch die Verschlüsselung verloren gehen. Und natürlich auch schon durch den Controller - aber der auf dem Board muss reichen, bis ich mal im Lotto gewonnen habe

H ist nen USB-Stick
Scheint doch gar nicht mal so unrealistisch zu sein.
bb
so, das war jetzt das letzte edit - die einzige (für mich) offensichtliche schwäche liegt an der mangelnden fehlerbehandlung und dem fehlenden RAII für file - aber ich wollts auch nich total übertreiben^^
-
Also der Code hat mich schon beeindruckt
Leider ist er in meinen Augen so komplex, das ich ihn, oder Teile davon, nicht übernehmen kann. Ich habe nicht nur mit der WinAPI Schwierigkeiten, sondern schon mit der OOP 
-
den timer musst du nicht verstehen, der rest sollte aber auch für einen anfänger relativ gut zu verstehen sein?!
wo liegt denn dein problem genau? oder beser: wo bist du denn in deinem buch und welches liest du denn?
-
Ich habe den 'Der C++ Programmierer' von Ulrich Breymann und bin im letzten Kapitel, bevor die OOP angeschnitten wird, genauer bei Programmstrukturierung.
Und falls Du die timer.hpp meinst, da erkenne ich nur durch die cout-Ausgaben, das sie wohl mit der Zeitmessung zusammen hängt und just die funktioniert bei mir ja einwandfrei.
-
na gut, dann lies ma noch paar kapitel, dann wirst dus auch versthen

-
Ich habe mal Dein Code bei mir kompilieren lassen und (ohne einen Zweifel gehabt zu haben ;)) die Werte waren auch bei mir realistisch.
Gibt es einen Grund, warum Du Deine Headerfiles .hpp genannt hast? Die werden doch sonst immer nur .h genannt?
-
lemon03 schrieb:
Ich habe mal Dein Code bei mir kompilieren lassen und (ohne einen Zweifel gehabt zu haben ;)) die Werte waren auch bei mir realistisch.
Gibt es einen Grund, warum Du Deine Headerfiles .hpp genannt hast? Die werden doch sonst immer nur .h genannt?
.hpp ist eine nette Abgrenzung zu C-Headern, wird fast öfters verwendet als .h
-
Wie macht man das denn in einer IDE? CodeBlocks zB bietet scheinbar nur h.files, cpp.files und leere Files an.
Ich kann mir kaum vorstellen, das man die dann händisch umbenennt?
-
Ahja, inzwischen ist es mir eingefallen. Einfach bei leeres File *.hpp eingeben.