![]() |
"Invalid Argument" bei read und write
Nabend!
Nachfolgender Codeausschnitt soll eine Liste von Dateien zusammenfügen. Es wird dabei die erste Datei genommen und der Inhalt der restlichen Dateien Schritt für Schritt so schnell wie möglich angehängt. Bei kleinen Dateien funktioniert das auch, aber bei mehreren zig MB Größe scheint ein Fehler aufzutreten, sowohl beim Einlesen, als auch beim Schreiben. Wenn ich immer nur 1 Byte gleichzeitig verarbeite, dann funktionierts fehlerfrei (ist aber zu langsam). Deshalb hab ich schon vermutet, dass es daran liegt, dass ich für den Zeiger "buffer" enorm viel Platz reservieren lasse - aber wenn das so in diesem Ausmaß nicht möglich ist, müsste mir das dann nicht der Compiler vorher sagen oder zumindest während der Programmausführung eine AV auftreten? Jedenfalls wird die Fehlervariable beim Öffnen der Datei und dem Setzen des Dateizeigers auf "Fehler 0" (kein Fehler) gesetzt, nur beim Lesen und Schreiben nachher sitzt sie auf "ungültiges Argument". Also manchmal regt mich C++ auf! Sowas hatte ich bei Delphi bisher noch nie erlebt :? ! Hat jemand von euch eine Ahnung, worin das Problem liegt? Laut der Hilfe kann read oder write maximal UINT_MAX-1 Bytes lesen/schreiben. Beste Grüße
Delphi-Quellcode:
…
int quelldatei, zieldatei; unsigned long long groesse, geschrieben = 0; char *buffer = new char[UINT_MAX]; zieldatei = open(Form1->Pfade->Strings[0].c_str(), O_WRONLY | O_BINARY, S_IREAD|S_IWRITE); lseek(zieldatei, 0, SEEK_END); for(unsigned long long i=1; i<Form1->Pfade->Count; i++) { quelldatei = open(Form1->Pfade->Strings[i].c_str(), O_RDWR | O_BINARY); groesse = lseek(quelldatei, 0, SEEK_END); lseek(quelldatei, 0, SEEK_SET); if(groesse > UINT_MAX-1) { //dieser Teil wird nicht ausgeführt geschrieben = groesse; while(geschrieben > UINT_MAX-1) { read(quelldatei, buffer, UINT_MAX-1); write(zieldatei, buffer, UINT_MAX-1); geschrieben -= UINT_MAX-1; } read(quelldatei, buffer, geschrieben); write(zieldatei, buffer, geschrieben); } else { //dieser Teil wird ausgeführt und die Fehlermeldungen werden ausgegeben read(quelldatei, buffer, groesse); Application->MessageBoxA(_sys_errlist[errno],"Quelldatei lesen"); write(zieldatei, buffer, groesse); Application->MessageBoxA(_sys_errlist[errno],"Zieldatei schreiben"); } close(quelldatei); } close(zieldatei); delete buffer; … |
Re: "Invalid Argument" bei read und write
Hi,
nur so ein Tipp (bin mir nicht sicher ob hier der Fehler liegt), versuch mal statt dem buffer die Adresse des ersten Elements zu übergeben, also:
Code:
Ich weiß nicht wie C++ Arrays aufgebaut sind, aber da sie von den normalen C-Arrays abweichen sollte hier buffer und &buffer[0] wieder etwas anderes sein, dann kann es schonmal krachen.
read(quelldatei, &buffer[0], groesse); Application->MessageBoxA(_sys_errlist[errno],"Quelldatei lesen");
write(zieldatei, &buffer[0], groesse); Application->MessageBoxA(_sys_errlist[errno],"Zieldatei schreiben"); Wie gesagt, nur eine Vermutung, Gruß Der Unwissende |
Re: "Invalid Argument" bei read und write
Hallo Andreas,
kennt dein C++-Compiler keinen stream i/o? Wenn nicht, dann halte ich 4GB für einen verdammt großen Puffer - 64KB wären wohl eher angebracht. Auch würde ich prüfen ob mindestens 2 Pfade vorhanden sind, bevor ich die Arbeit aufnehme. Die Laufvariable i scheint mir auch hoffnungslos überdimensioniert zu sein. Warum öffnest du die Quelldateien für Lesen und Schreiben? Musst du die Größe der Quelldatei durch lseek() bestimmen? Das geht bestimmt auch direkt (fsize?) über die Metadaten im Verzeichniseintrag. Die Verarbeitungsschleife scheint mir unbrauchbar zu sein. Ein brauchbares Muster stelle ich mir etwa so vor:
Code:
Hierbei unterstelle ich, dass die Schreib- und Leseaufrufe die tatsächlich verarbeiteten Mengen zurückgeben.
// ...
rest = groesse; while (rest > 0) { gelesen = read(quelldatei, buffer, BUF_SIZE); geschrieben = write(zieldatei, buffer, gelesen); rest -= geschrieben; } // ... Freundliche Grüße vom marabu |
Re: "Invalid Argument" bei read und write
ok, ich danke euch zunächst erstmal.
vorweg: ich hatte in diesen tagen nicht die zeit gefunden, mich wieder mit diesem problem zu befassen, aber ich habe ein frage an dich, marabu: warum ausgerechnet 64KB als puffergröße? gut, 4gb is sehr viel, da habe ich garnicht dran gedacht, geschweige denn, es mal vorsichtshalber ausgerechnet. ähm, wird jedem prozess nicht maximal 4gb zugesprochen? dann hätte doch eine fehlermeldung kommen müssen, oder nicht? weil auf diese pufferreservierung von 4gb würde doch dann noch ein bisschen vom programm an sich heraufkommen? ja, stimmt, die laufvariable braucht nicht so groß sein, weil sie ja immer mit der anzahl der einträge in der listbox verglichen wird, welche als rückgabewert von typ integer ist. ich würde gerne so viele listboxeinträge wie möglich aufnehmen können, was bei integer nicht in dem ausmaß wie bei unsigned long long möglich ist - frage: was passiert, wenn die maximale anzahl an einträgen überschritten wird? ... ok, hab gerade mal nachgeschaut, das wären ungefähr 2 milliarden einträge, dürfte also erstmal reichen :mrgreen: ! ich weiß garnicht mehr, warum ich die dateigröße über fseek ermittle, es gab jedenfalls irgendein problem bei fsize, kann jetzt aber nicht sagen, was das noch war :| - ich glaube, fsize lieferte manchmal inkorrekte rückgabewerte... vielleicht auch in verbindung damit, wenn währenddessen die datei von nem anderen programm geöffnet war (fileseek kann zwar in diesem fall auch nicht gesetzt werden, liefert jedoch -1 zurück, wodurch ich diesen fehlerfall überhaupt erkennen kann). |
Re: "Invalid Argument" bei read und write
Hi,
die 64KB kommen aus dem Bauch. Den worst case hast du ja schon mit deinem single byte i/o erlebt. Beim file i/o überlagern sich ja mehrere Puffer auf verschiedenen Ebenen. Die performance deines Programms steigt mit wachsender Puffergröße an, fällt allerdings irgendwann auch wieder ab, wenn der Puffer zu groß gewählt wird. Mit einem kleinen Testprogramm (100 Zeilen schätze ich) könntest du den optimalen Durchsatz ausloten. Gute Nacht |
Re: "Invalid Argument" bei read und write
Zitat:
|
Re: "Invalid Argument" bei read und write
Ja sicher doch. Die einzelnen Pufferbereiche sind ja unterschiedlich groß. Die Festplatte selbst hat einen Track Buffer und einen Cache, der von Modell zu Modell variieren kann. Das Dateisystem hat einen Cache, der von der Größe des Hauptspeichers und dem momentanen Verhandlungsstand der Betriebssystem-Komponenten abhängt, ...
Warum hängst du die Dateien nicht einfach per shell command hintereinander?
Code:
Freundliche Grüße
copy /b quelle-*.dat ziel.dat
|
Re: "Invalid Argument" bei read und write
Zitat:
das programm copy arbeitet doch bestimmt auch so, gell? wie viele bytes verarbeitet es selber denn gleichzeitig? ich möchte nachher nicht langsamer sein, als copy. :nerd: beste grüße |
Re: "Invalid Argument" bei read und write
Zur Puffergröße:
ich hab beim meinem Rechner und mit verschiedenen Laufwerken (Puffern) die grenze bei 2*515 KB gelegt. Ab 2*1 MB (paralell auf einer Platte gelesen) fiehl die Datenrate wieder ab. eine 2-Potenz als Größe ist eigentlich am Besten. Ansonsten macht sich wohl das 4- bis 8-fache der "größtens" Blocks recht angenehm. Von den leicht ermittelbaren Größen lassen sich wohl der Windowsseitenspeicher (aktuell 64 KB je Block) und dann noch die Clustergröße der Festplatte ermitteln. |
Re: "Invalid Argument" bei read und write
Zitat:
Zitat:
Delphi-Quellcode:
ich müsste also am besten weniger als 2^21 Bytes verarbeiten? hängt diese schranke allerdings von den besagten größen (clustergröße, windowsseitenspeicher) ab? wie bekomme ich diese werte und in welchem zusammenhang stehen sie formeltechnisch?
oben := 2048*1024 Byte = 2097152 Byte
ld oben = potenz ln oben / ln 2 = ld oben = 21 2^21 Bytes = oben beste grüße |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:42 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz