Probleme mit eigener Kopierroutine

Für allgemeine Fragen zur Programmierung mit PureBasic.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag 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.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag 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. :(
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag 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....
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag 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.
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Benutzeravatar
HeX0R
Beiträge: 3056
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Beitrag 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.
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Negativ.

Habe gerade die v4.10B3 upgedated. Code bleibt an gleicher Stelle stehen o.O.
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Benutzeravatar
HeX0R
Beiträge: 3056
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Beitrag von HeX0R »

Tatsächlich ?
Wie gross ist denn die Datei, die du kopieren willst ?
Ich habs natürlich nur mal mit ner Furzdatei versucht.
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Das scheint mir keine Rolle zu spielen... Beim 1. zugriff gibts schon Probleme...
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Benutzeravatar
HeX0R
Beiträge: 3056
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Beitrag von HeX0R »

Benutzt du einen Callback ?
Bzw. ginge es ohne den ?
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Mit Callback
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Antworten