Probleme mit eigener Kopierroutine

Für allgemeine Fragen zur Programmierung mit PureBasic.
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Probleme mit eigener Kopierroutine

Beitrag von Agent »

Hallo PBler.

Ich habe mit eine eigene Kopierroutine geschrieben. Grund dafür ist, das der CopyFile-Befehl zu "unflexibel" ist und kein Progress unterstützt. Leider ist mir nachdem ich die Procs schon einige Zeit nutze nun aufgefallen, das offensichtlich bei einer bestimmten Dateigröße es Probleme gibt.

Unzählige Dateien funktionieren perfekt. Aber eine Testdatei wird nicht komplett geschrieben.

Jemand eine Idee?

Hier der Code:

Code: Alles auswählen

EnableExplicit

Procedure SK_CopyFile(sourcefile$, targetfile$, OverwriteExistingFile.b=#True, *ProgressRoutine.l=0, fPackSize.f=0)
  
  ; Definitionen
  Define.f fSourceFileLen, fSourceFilePos, fPackSize
  Define.l lSourceFile, lTargetFile, result
  Define.l Memory.MEMORYSTATUS
  Define.f *CopyBuffer, DataReaded
  Define.b bGlobalAbort, UTC_Korrektur

  ; 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!
  result=#SK_CopyFile_Failed


  ; Progress-Routine (Aufbaubeispiel)
        ; Procedure SK_CopyFile_ProgressCallback(act_pos, filesize)
        ;   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 = ReadFile(#PB_Any, sourcefile$)   
  fSourceFilePos.f = 0
    
  If lSourceFile ; Quelle öffnen ok?
    
    ; Zieldatei erzeugen
    lTargetFile = CreateFile(#PB_Any, targetfile$)
    If lTargetFile ; Ziel öffnen ok?
      
      ; Wieviel arbeit liegt vor uns
      fSourceFileLen.f=Lof(lSourceFile) ; Dateigröße ermitteln
      
      If fSourceFileLen > 0 ; Quelle eine 0-Byte-Datei?
        
        ; Paketgröße ermitteln
        If fPackSize = 0 ; Dynamische Paketgröße              
          GlobalMemoryStatus_(Memory.MEMORYSTATUS)
          If fSourceFileLen < 3145728 ; 3 MB
            fPackSize = fSourceFileLen
          ElseIf (fSourceFileLen/100) < (Memory\dwAvailPhys / 4)
            fPackSize = fSourceFileLen / 100
          Else
            fPackSize = (Memory\dwAvailPhys / 1000)
          EndIf
        EndIf
        
        ; Falls ProgressCallback: Startwert eintragen, damit User sieht es passiert was
        If *ProgressRoutine <> 0
          CallFunctionFast(*ProgressRoutine, 1, fSourceFileLen)
        EndIf

        ; Speicher reservieren für Blocks...
        *CopyBuffer = AllocateMemory(fPackSize)
        
        If *CopyBuffer ; Speicher ok? Dann los!
        
          Repeat
            
            ; Haben wir einen Rest zu kopieren?
            If fSourceFilePos+fPackSize > fSourceFileLen
              fPackSize = fSourceFileLen-fSourceFilePos ; Restdaten ermitteln
              If fPackSize>0 ; Nur Speicher reservieren, wenn ein Rest vorhanden
                *CopyBuffer = ReAllocateMemory(*CopyBuffer, fPackSize)
              Else ; Kein Rest -> raus hier, da stimmt was nicht
                result = #SK_CopyFile_Failed
                Break
              EndIf
            EndIf
            
            ; Daten aus Quelle einlesen
            DataReaded = ReadData(lSourceFile, *CopyBuffer, fPackSize)
            
            If DataReaded > 0 ; Daten korrekt gelesen? Dann ab in die Zieldatei
              WriteData(lTargetFile, *CopyBuffer, DataReaded)                
              fSourceFilePos + DataReaded  
              
            ElseIf DataReaded = 0 And fSourceFilePos < fSourceFileLen ; Ui, da ging was schief
              result = #SK_CopyFile_Failed
              ;Break
            EndIf
          
            ; Progress aktualisieren
            If *ProgressRoutine <> 0 And DataReaded > 0
              CallFunctionFast(*ProgressRoutine, fSourceFilePos, fSourceFileLen)
            EndIf
            
          Until fSourceFilePos >= fSourceFileLen Or DataReaded=0 Or bGlobalAbort=#True
    
; NUR FÜR TEST
Debug "FINISHED"
Debug DataReaded
Debug fSourceFilePos
Debug fSourceFileLen
                    
          If bGlobalAbort = #True ; Hat User abgebrochen?
            result = #SK_CopyFile_UserAbort
          EndIf
          
          If fSourceFileLen <> fSourceFilePos ; Gibts Probleme mit den Dateigrößen? Differenzen?
            result = #SK_CopyFile_TargetCorrupt
            Debug "Source <> Target"
          EndIf
                      
          ; Speicher wieder freigeben!
          FreeMemory(*CopyBuffer)
          
        Else
          result = #SK_CopyFile_MemoryError ; Probleme beim Speicher reservieren
        EndIf
        
      Else
        result = #SK_CopyFile_0ByteFile ; War ne 0-Byte-Datei
      EndIf
      
      ; Zieldatei wieder schließen
      CloseFile(lTargetFile)

    Else
      result = #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, fSourceFileLen, fSourceFileLen)
    EndIf
        
    result = #SK_CopyFile_OK ; Super, alles ok
  Else
  
    result = #SK_CopyFile_CannotOpenSource ; Quelle konnte nicht geöffnet werden :(
  EndIf
    
  ProcedureReturn result
EndProcedure


; TESTLAUF

; Probleme mit einer Datei festgestellt. Quell-Dateigröße: 60366336 Bytes. Ziel nach Copy: 60366265 ????
; Duzende anderen Datein funktionieren. Liegts an der Dateigröße???

Define.s testfile$
testfile$ = "CaromV482.exe"
;testfile$ = "ReactOS-LiveCD.iso"
Debug SK_CopyFile("D:\1\"+testfile$, "D:\2\"+testfile$)
Debug FileSize("D:\1\"+testfile$)
Debug FileSize("D:\2\"+testfile$)
SetClipboardText(Str(FileSize("D:\2\"+testfile$)))

Vielen Dank im vorraus.
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
NicknameFJ
Beiträge: 324
Registriert: 03.06.2007 14:36
Wohnort: Von der Sonne aus gesehen der dritte Planet

Beitrag von NicknameFJ »

Hallo !

Wenn es nur um die Progress-Funktionalität geht gibt es hier im Forum glaube ich schon was - habe ich kürzlich hier? gelesen

Probiere mal die Suchfunktion mit "filecopy progress" - wenn ich mich nicht täusche wird dies sogar von der API Filecopy-Funktion unterstützt !

Grüße

Joachim


/Edit: hier der LINK zum Beitrag

http://www.purebasic.fr/german/viewtopi ... y+progress
PS: Alle im Text enthaltenen Schreibfehler sind beabsichtigt und dienen der Belustigung aller

Bild
Benutzeravatar
Ligatur
Beiträge: 196
Registriert: 09.07.2006 00:41

Beitrag von Ligatur »

Hallo,
gucke doch mal im Codearchive nach WinAPI-FileOperations.pb (falls du unter Windows arbeitest).
Grüße,
Ligatur
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Hallo.

Danke für eure Antworten. ABer mir geht es nicht um irgendeine Kopierroutine mit Progress. Dafür habe ich was aus der API.

Ich suche den Fehler in meiner EIGENEN Kopierroutine. Diese bietet mir mehr Möglichkeiten. Hat jemand eine Idee warum nur bei bestimmten Dateien ein winziger Teil am Ende nicht kopiert wird?

Diesen Teil habe ich mehr oder weniger nur aus Verzweiflung zum Schluß hinzugefügt, da er eigentlich überflüssig ist. READEDDATA liefert eigentlich ja immer die Anzahl der gelesenen Bytes...

Code: Alles auswählen

            ; Haben wir einen Rest zu kopieren? 
            If fSourceFilePos+fPackSize > fSourceFileLen 
              fPackSize = fSourceFileLen-fSourceFilePos ; Restdaten ermitteln 
              If fPackSize>0 ; Nur Speicher reservieren, wenn ein Rest vorhanden 
                *CopyBuffer = ReAllocateMemory(*CopyBuffer, fPackSize) 
              Else ; Kein Rest -> raus hier, da stimmt was nicht 
                result = #SK_CopyFile_Failed 
                Break 
              EndIf 
            EndIf 
Man(n) könnte dies also getrost weglassen. Trotzdem ändert sich die Größe der Zieldatei durch diesen Codeschnipsel!

Jemand Ideen? Wäre super wenn wir das lösen könnten ;)
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 »

leider hab ich keinen bock, deinen code durchzuackern.
daher werde ich mich mal theoretisch äußern, und du kannst theoretisch antworten.

wenn du deine vorgehensweise auch in worten beschreiben könntest, kommen wir so weiter.

...

ich könnte mir denken, dass du die ende-prüfung zum falschen zeitpunkt durchführst.

wenn ich mich recht entsinne, liefert das kommando zum einlesen
eines buffers ein flag zurück, ob weitere daten vorhanden sind.
wenn du dieses Flag als Ende-Bedingung für deine schleife nimmst,
köntest du einen durchlauf zu früh aussteigen.

Code: Alles auswählen

While BufferLesen() = NochMehr
  BufferSchreiben()
Wend
funktioniert nicht, weil der letzte buffer nicht mehr geschrieben wird.

Code: Alles auswählen

Repeat
  NochMehr = BufferLesen()
  BufferSchreiben()
Until Not NochMehr
hingegen funktioniert.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Captn. Jinguji
Beiträge: 397
Registriert: 07.06.2005 19:47
Computerausstattung: PB 4.73x64, i7, WIN 10x64, ATI NVidia RTX 2070
Wohnort: Witten

Beitrag von Captn. Jinguji »

Öhmmmm kann das sein, dass Du Dich bei Deine Variablendefinitionen mit .f und .l oder.q vertan hast ?
Wieso sind da so viele Variablen als float definiert ? Leuchtet mir gar nicht recht ein.

Oder ist da ein besonderer Trick dabei ?
Ist das Kunst hier, oder kann das weg ?
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8820
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Stimmt, Float sollte bei solchen Dingen nichts zu suchen haben.
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Hi.

Hm...das Hilft mir leider alles nichts. Niemand hat sich wirklich damit auseinander gesetzt. Naja.

BTW:
Warum kein Float? Hab ich was verpasst? Ich meine, es gäbe a) .long, dann dürften die Dateien aber nicht besonders groß sein oder b) .float, dann dürfen die Dateien schon im Terrabyte bereich liegen, nachkommastellen werden nicht benötigt (Kommastelle ist ja shiftbar) oder d) .quad - scheint mir mächtig übertrieben und verbraucht zuviel Speicher und ist zu lahm.

Oder verstehe ich hier was falsch?
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 »

yap, definitiv.
Long ist immer genau, Float ist immer ungenau.

benutze Long, und wenn dir das nicht reicht eben Quad, aber niemals Float!
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 »

Wie?

float ist ungenau? Willst du mir sagen, entweder Long reicht oder es muss Quad sein? Dateigrößen sind doch immer Ganzzahlen ohne Nachkommastellen. Da interessiert doch die Nachkommastelle nicht.. Da war mir float bisher am besten. Zumal float nur 4 Byte im Speicher benötigt, quad gleich 8. Long kommt für Dateigrößen wohl kaum in Frage. Aus dem Zeitalter sind wir wohl raus.
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