Seite 2 von 3
Verfasst: 25.09.2007 22:42
von Kaeru Gaman
ne denk doch mal nach....
Float benutzt 4 byte, Long benutzt 4 byte.
Float benutzt ein paar Bit für den Exponenten, Long nicht, das ist Ganzzahl.
die Information ist begrenzt auf 2^32 verschiedene zustände.
mehr kann man nicht speichern.
im Bereich von 0 bis 2147483647 ist Long
absolut genau.
aber Float kann 2147483647.0 schon nicht mehr genau darstellen,
weil ein paar Bit für den Exponenten benutzt werden.
demo:
Code: Alles auswählen
a.f = 2147483600
b.l = 2147483600
Debug a
Debug b
a+1
b+1
Debug a
Debug b
a+1
b+1
Debug a
Debug b
siehst du?
nicht nur, dass Float die Zahl beim ersten aufruf ungenau wiedergibt,
es ist nicht fähig, eine kleine addition zu verarbeiten.
das liegt nicht an PB, das liegt an der Natur der Fließkommazahlen.
der selbe Algorithmus wird dir in C++ oder Java oder wo auch immer
das selbe Ergebnis liefern, wenn du einen 32bit-variablen-typ wählst.
mit 64bit (Double) kannst du das Problem
verlagern, aber nicht eliminieren.
Verfasst: 25.09.2007 23:28
von Agent
So, ich hab die Routine mal auf Quad umgestellt (und unsinniges rausgenommen):
Code: Alles auswählen
Procedure SK_CopyFile(sourcefile$, targetfile$, OverwriteExistingFile.b=#True, *ProgressRoutine.l=0, qPackSize.q=0)
; Definitionen
Define.q qSourceFileLen, qSourceFilePos, qPackSize
Define.q *CopyBuffer, qDataReaded
Define.l lSourceFile, lTargetFile, lResult
Define.l Memory.MEMORYSTATUS
; Rückgabe-Codes definieren
#SK_CopyFile_Failed = 0 ; #False
#SK_CopyFile_OK = 1 ; #True
#SK_CopyFile_0ByteFile = 2 ; Quell-Datei ist 0 Byte groß
#SK_CopyFile_UserAbort = -1 ; User hat abgebrochen
#SK_CopyFile_FileNotFound = -2 ; Quell-Datei nicht gefunden
#SK_CopyFile_CannotOpenSource = -3 ; Konnte Quelle nicht öffnen
#SK_CopyFile_CannotCreateTarget = -4 ; Konnte Zieldatei nicht anlegen
#SK_CopyFile_TargetCorrupt = -5 ; Source-Size und Target-Size sind unterschiedlich. Ggf, Speicher voll.
#SK_CopyFile_MemoryError = -6 ; Konnte Speicher nicht reservieren
; Standard-Wert für Rückgabe: Fehler!
lResult=#SK_CopyFile_Failed
; Progress-Routine (Aufbaubeispiel)
; Procedure SK_CopyFile_ProgressCallback(act_pos.q, filesize.q)
; If filesize>0
; percentage_done = (act_pos*100)/filesize
; Else
; percentage_done = 100
; EndIf
; SetGadgetState(#main_progressbar_file, percentage_done)
; EndProcedure
; Gibt es Zieldatei schon: User fragen wie es weiter gehen soll!
If FileSize(targetfile$)>0 And OverwriteExistingFile=#False ; Ziel existiert, User will gefragt werden!
If MessageRequester("","Möchten Sie folgende Datei überschreiben?"+#CRLF$+#CRLF$+targetfile$, #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
ProcedureReturn #SK_CopyFile_UserAbort
EndIf
EndIf
; Quelle öffnen
lSourceFile = OpenFile(#PB_Any, sourcefile$)
qSourceFilePos = 0
If IsFile(lSourceFile) ; Quelle öffnen ok?
; Zieldatei erzeugen
lTargetFile = CreateFile(#PB_Any, targetfile$)
If IsFile(lTargetFile) ; Ziel öffnen ok?
; Wieviel arbeit liegt vor uns
qSourceFileLen=Lof(lSourceFile) ; Dateigröße ermitteln
If qSourceFileLen > 0 ; Quelle eine 0-Byte-Datei?
; Paketgröße ermitteln
If qPackSize = 0 ; Dynamische Paketgröße
GlobalMemoryStatus_(Memory.MEMORYSTATUS)
If qSourceFileLen < 3145728 ; 3 MB
qPackSize = qSourceFileLen
ElseIf (qSourceFileLen/100) < (Memory\dwAvailPhys / 4)
qPackSize = qSourceFileLen / 100
Else
qPackSize = (Memory\dwAvailPhys / 1000)
EndIf
EndIf
; Falls ProgressCallback: Startwert eintragen, damit User sieht es passiert was
If *ProgressRoutine <> 0
CallFunctionFast(*ProgressRoutine, 1, qSourceFileLen)
EndIf
; Speicher reservieren für Blocks...
*CopyBuffer = AllocateMemory(qPackSize)
If *CopyBuffer ; Speicher ok? Dann los!
Repeat
; Daten aus Quelle einlesen
qDataReaded = ReadData(lSourceFile, *CopyBuffer, qPackSize)
If qDataReaded > 0 ; Daten korrekt gelesen? Dann ab in die Zieldatei
WriteData(lTargetFile, *CopyBuffer, qDataReaded)
qSourceFilePos + qDataReaded
ElseIf qDataReaded = 0 And qSourceFilePos < qSourceFileLen ; Ui, da ging was schief
lResult = #SK_CopyFile_Failed
EndIf
; Progress aktualisieren
If (*ProgressRoutine <> 0) And (qDataReaded > 0) And (qSourceFilePos < qSourceFileLen)
CallFunctionFast(*ProgressRoutine, qSourceFilePos, qSourceFileLen)
EndIf
Until qSourceFilePos >= qSourceFileLen Or qDataReaded=0 Or bGlobalAbort=#True Or bMainExit=#True
If bGlobalAbort = #True ; Hat User abgebrochen?
lResult = #SK_CopyFile_UserAbort
EndIf
If qSourceFileLen <> qSourceFilePos ; Gibts Probleme mit den Dateigrößen? Differenzen?
lResult = #SK_CopyFile_TargetCorrupt
Debug "Source <> Target"
EndIf
; Speicher wieder freigeben!
FreeMemory(*CopyBuffer)
Else
lResult = #SK_CopyFile_MemoryError ; Probleme beim Speicher reservieren
EndIf
Else
lResult = #SK_CopyFile_0ByteFile ; War ne 0-Byte-Datei
EndIf
; Zieldatei wieder schließen
CloseFile(lTargetFile)
Else
lResult = #SK_CopyFile_CannotCreateTarget ; Zieldatei konnte nicht angelegt werden
EndIf
; Quelldatei wieder schließen
CloseFile(lSourceFile)
; Datum und Attribute wie Originaldatei setzen
SetFileDate(targetfile$, #PB_Date_Created, AddDate(GetFileDate(sourcefile$, #PB_Date_Created), #PB_Date_Hour, UTC_Korrektur))
SetFileDate(targetfile$, #PB_Date_Modified, AddDate(GetFileDate(sourcefile$, #PB_Date_Modified), #PB_Date_Hour, UTC_Korrektur) )
SetFileAttributes(targetfile$, GetFileAttributes(sourcefile$)) ; Attribute angleichen
; Progress lieber nochmal auf 100% setzen
If *ProgressRoutine <> 0
CallFunctionFast(*ProgressRoutine, qSourceFileLen, qSourceFileLen)
EndIf
lResult = #SK_CopyFile_OK ; Super, alles ok
Else
lResult = #SK_CopyFile_CannotOpenSource ; Quelle konnte nicht geöffnet werden :(
EndIf
ProcedureReturn lResult
EndProcedure
Jetzt bricht die Routine bei
Code: Alles auswählen
qDataReaded = ReadData(lSourceFile, *CopyBuffer, qPackSize)
ab, mit dem Fehler: #File object not initialized.
Wie das denn? Datei ist definitiv offen. Geprüft mit IsFile(). Mit floats oder longs ging das noch. Das war auch der Grund warum ich von ursprünglich Quad wieder weg bin. Früher war die Routine mal mit Quads. Aber genau da lag das Problem.

Verfasst: 26.09.2007 00:24
von Kaeru Gaman
welcher PB-version?
die Quads sind in 4.00 neu gekommen, und waren noch nicht komplett ausgereift.
ein paar quad-fehler sind auch in der 4.02 stable noch drin.
in der 4.10 beta sind sie aber behoben.
das nur mal auf die schnelle, ich hab deinen code jetzt nicht nach Human-Bugs auseinandergepflückt....
Verfasst: 26.09.2007 09:21
von Agent
Hi.
PB v4.02.
Habe noch ein wenig experimentiert und die zu lesenende Puffergröße mal auf ein max. von LONG gestellt, da ich hier das Problem vermutete. Nutzlos.
ReadData() arbeitet nicht, wenn der Rückgabewert in eine QUAD geschrieben werden soll.
Verfasst: 26.09.2007 09:35
von HeX0R
Mit PB4.1B3 funktioniert dein Code Wonderbra!
Allerdings würde ich vorschlagen Variablen in Prozeduren nicht zu "definen", sondern zu Protecten:
Code: Alles auswählen
; Definitionen
Protected qSourceFileLen.q, qSourceFilePos.q
Protected *CopyBuffer, qDataReaded.q
Protected lSourceFile.l, lTargetFile.l, lResult.l
Protected Memory.MEMORYSTATUS
Define macht eher Sinn ausserhalb von Prozeduren.
Verfasst: 26.09.2007 10:55
von Agent
Negativ.
Habe gerade die v4.10B3 upgedated. Code bleibt an gleicher Stelle stehen o.O.
Verfasst: 26.09.2007 11:52
von HeX0R
Tatsächlich ?
Wie gross ist denn die Datei, die du kopieren willst ?
Ich habs natürlich nur mal mit ner Furzdatei versucht.
Verfasst: 26.09.2007 11:55
von Agent
Das scheint mir keine Rolle zu spielen... Beim 1. zugriff gibts schon Probleme...
Verfasst: 26.09.2007 11:56
von HeX0R
Benutzt du einen Callback ?
Bzw. ginge es ohne den ?
Verfasst: 26.09.2007 11:57
von Agent
Mit Callback