|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Berkeley
Anmeldungsdatum: 13.05.2024 Beiträge: 84
|
Verfasst am: 19.05.2024, 22:23 Titel: Binärdatei lesen (und speichern) |
|
|
Code: |
DIM AS BYTE PTR buffer
DIM AS INTEGER fn, i
buffer=ALLOCATE(500)
fn=FREEFILE
IF OPEN("file.dat" FOR INPUT AS #fn)=0 THEN
i=LOF(fn)
buffer=ALLOCATE(i)
GET #fn, 0, buffer, i
CLOSE #fn
ENDIF |
funktioniert so und ähnlich ums Verrecken nicht, genausowenig wie PUT # |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1267 Wohnort: Ruhrpott
|
Verfasst am: 20.05.2024, 05:49 Titel: |
|
|
Hallo,
Dateien, auf die mit GET oder PUT zugegriffen wird, müssen als BINARY geöffnet werden. Außerdem steht das erste Byte der Datei an Position 1, nicht an Position 0.
Und wenn du dem Pointer buffer einen neuen Speicherbereich zuweist, ohne den alten vorher zu deallozieren, bekommst du ein Speicherleck.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Berkeley
Anmeldungsdatum: 13.05.2024 Beiträge: 84
|
Verfasst am: 20.05.2024, 11:30 Titel: |
|
|
Danke für die Antwort. Die Dokumentation ist "nicht sehr gut". So einfach und "Anfängerfehler" ist es aber nicht. Anscheinend will GET # (unter Windows) trotz offensichtlichem Datentyp BYTE einen achtmal größeren Speicherblock einlesen, was die Datei nicht mal hergibt.
Nicht gut, vorallem wenn sich FreeBASIC womöglich je nach Version/Plattform anders verhält. Ich muss schauen, dass ich funktionierenden Beispielcode finde. "BINARY", "OUTPUT" und "INPUT" machen keinen Unterschied (und Sinn). Auf den Puffer muss auch byteweise zugegriffen werden können. |
|
Nach oben |
|
|
Berkeley
Anmeldungsdatum: 13.05.2024 Beiträge: 84
|
Verfasst am: 20.05.2024, 13:33 Titel: |
|
|
Die Lösung:
Code: |
DIM AS UBYTE buffer()
DIM AS INTEGER buffersize
DIM AS INTEGER fileno
IF OPEN("data.dat" FOR BINARY AS #fileno)=0 THEN
buffersize=LOF(fileno)
REDIM buffer(buffersize-1)
GET #fileno, 1, buffer()
PUT #fileno, 1, buffer()
CLOSE #fileno
ENDIF
|
Ob "BINARY" oder "INPUT"/"OUTPUT" scheint keine Rolle zu spielen. Eigentlich sollte man "BINARY ACCESS [READ|WRITE]" schreiben, und bei "INPUT" und "OUTPUT" kann man stattdessen ein Encoding angeben, u.a. "utf8".
LOF() gibt bei mir die Länge um 1 zu groß zurück. Alles in allem nicht sehr gut gemacht :-/ Und wenn schon das Offset 0 einem Index/Stelle 1 entsprechen soll, dann sollte man es konsequent durchziehen; myData(0) sei dann immer falsch, und mit DIM myData(10) gibt es auch ein myData(10) bzw. ist das letzte Feld...
Auf der anderen Seite sollte man beim Programmieren halt auch lernen, wie Computer arbeiten. Von daher ist schwierig was besser ist. Natürlich gibt es im RL keine "Fußnote [0]", man beginnt immer mit "1" zu zählen, hat eine 1. Stelle und keine 0., und wenn man eine Schnittstelle für Menschen programmiert, muss man den Index +1 ausgeben... |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4683 Wohnort: ~/
|
Verfasst am: 20.05.2024, 19:03 Titel: |
|
|
Sicherheitshalber mal dazu gesagt: Ein (wasauchimmer) PTR ist immer so groß wie ein INTEGER. Ein BYTE ist 8 Bit groß, ein BYTE PTR dagegen 32 bzw. 64 Bit, je nach Plattform. Ich nehme auch an, dass du Bytes einlesen willst und keine Byte-Adressen?
Das mit dem Start bei 0 oder bei 1 ist in FreeBASIC leider recht inkonsequent; das ist ein Erbe aus QBasic.
Nachtrag: Ich bin mir nicht sicher, aber dass LOF "um 1 zu groß" ist, könnte an einem EOF-Zeichen liegen, mit denen Dateien normalerweise beendet werden, die aber meist ignoriert werden. Weiß da jemand mehr? _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1267 Wohnort: Ruhrpott
|
Verfasst am: 20.05.2024, 20:55 Titel: |
|
|
Berkeley hat Folgendes geschrieben: | Ob "BINARY" oder "INPUT"/"OUTPUT" scheint keine Rolle zu spielen.
| Das stimmt nicht. Beim Öffnen mit OUTPUT wird die Datei neu angelegt, hat also eine Größe von 0. Und in eine mit INPUT geöffnete Datei kann man nicht schreiben.
Berkeley hat Folgendes geschrieben: | Eigentlich sollte man "BINARY ACCESS [READ|WRITE]" schreiben, und bei "INPUT" und "OUTPUT" kann man stattdessen ein Encoding angeben, u.a. "utf8".
| ACCESS dient nur dazu, versehentliche unerwünschte Zugriffe (üblicherweise Schreibzugriffe) im weiteren Programmverlauf zu verhindern. Standardmäßig ist eine BINARY-Datei zum Lesen und Schreiben geöffnet. Eine Encoding-Angabe macht nur bei Textdateien Sinn. Mit INPUT und OUTPUT lassen sich aber auch alle anderen Arten von Daten lesen oder schreiben.
Berkeley hat Folgendes geschrieben: | LOF() gibt bei mir die Länge um 1 zu groß zurück.
| Das stimmt nicht. Wenn LOF() einen Wert von z.B. 100 zurückgibt, dann ist die Datei auch 100 Bytes groß. Eventuell handelt es sich um einen Text mit angehängtem Zeilenumbruch (CR/LF bei Windows, LF bei Linux).
Berkeley hat Folgendes geschrieben: | Alles in allem nicht sehr gut gemacht :-/ Und wenn schon das Offset 0 einem Index/Stelle 1 entsprechen soll, dann sollte man es konsequent durchziehen; myData(0) sei dann immer falsch, und mit DIM myData(10) gibt es auch ein myData(10) bzw. ist das letzte Feld...
| Das ist eines der Fallstricke von FB. Arrays beginnen standardmäßig mit dem Index 0, sofern nicht explizit etwas anderes angegeben wird. Die Indices von myData(10) gehen von 0 bis 10, das sind 11 Elemente.
Dein Codeschnipsel enthält noch einen Fehler, denn die Dateinummer muß zwischen 1 und 255 liegen. Ein Öffnungsversuch mit Dateinummer 0 produziert einen Fehler.
Zur Veranschaulichung habe ich deinen Code mal erweitert: Code: | ReDim As UByte buffer()
Dim As Integer buffersize
Dim As Integer fileno = FreeFile
Open "data.dat" For Binary As #fileno
Print #fileno, "Hallo Welt"
Close fileno
If Open("data.dat" For Binary As #fileno)=0 Then
buffersize=Lof(fileno)
? "buffersize = ";buffersize
?
? "LBound ="; LBound(buffer), "UBound = "; UBound(buffer)
ReDim buffer(buffersize-1)
? "LBound ="; LBound(buffer), "UBound = "; UBound(buffer)
?
Get #fileno, 1, buffer()
For x As Integer = LBound(buffer) To UBound(buffer)
? x, buffer(x), Chr(buffer(x))
Next
?
Put #fileno, 1, buffer()
? "LOF = ";Lof(fileno)
Close #fileno
Else
? "FEHLER"
EndIf
Sleep |
Guß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Berkeley
Anmeldungsdatum: 13.05.2024 Beiträge: 84
|
Verfasst am: 20.05.2024, 21:24 Titel: |
|
|
Das Codeschnipsel war nur ne Veranschaulichung - quasi von der Syntax, ergibt aber keinen Sinn. Von daher egal ob es funktionieren kann. Und "sauberer" Code ist natürlich viel umfangreicher, wie eben das ELSE für die Fehlerbehandlung...
- Stimmt das wirklich, dass man mit DIM x(10) 11 Elemente kriegt ??? Dann war DAS der Bug. Ich habe wohl den REDIM mit dem LOF-Wert -1 gemacht, und dann den LOF-Wert gedumpt und geglaubt, das wär' LOF-1. Da man mit PUT# anscheinend nicht bytegenau schreiben kann, sondern nur die Puffer in voller Länge, war daher die Datei dann um 1 zu groß.
Was ich mit "scheint keine Rolle zu spielen" meinte ist, dass es bezüglich Binärzugriffen keine unerwartbaren Unterschiede gibt. Da Random Access, wird es nur höchstwahrscheinlich keine neue Datei erzeugen und natürlich auch nicht wie APPEND ans Ende einer Datei dranschreiben. Vermutlich spielt das Encoding irgendeine Rolle, wenn man PRINT# und/oder INPUT# benutzt, sehe aber keinen Sinn darin. Ob UTF-8 oder ASCII müssten normal die Stringfunktionen machen, nicht die Dateifunktionen.
Ziemlicher Faux Pas, dass man sich auf die QBasic-Kompatibilität versteift hat. Aus meiner Sicht könnte man ja über die Compiler-Flags alte QBasic-Projekte kompilierbar machen, und mit FreeBASIC eine erheblich abweichende Syntax umsetzen... |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4683 Wohnort: ~/
|
Verfasst am: 20.05.2024, 21:53 Titel: |
|
|
Zitat: | - Stimmt das wirklich, dass man mit DIM x(10) 11 Elemente kriegt ??? |
Ja - ein DIM(10) macht dasselbe wie ein DIM(0 TO 10).
Für binären Zugriff spielt das Encoding keine Rolle, das ist richtig. Binärdaten sind halt Binärdaten.
Zitat: | Ziemlicher Faux Pas, dass man sich auf die QBasic-Kompatibilität versteift hat. Aus meiner Sicht könnte man ja über die Compiler-Flags alte QBasic-Projekte kompilierbar machen, und mit FreeBASIC eine erheblich abweichende Syntax umsetzen... |
FreeBASIC war halt zunachst als "QBasic-Klon" angelegt und hat sich erst ab v0.17 deutlich davon abgehoben. Und ab diesem Zeitpunkt war es nicht nur eine Frage, zu QBasic kompatibel zu sein (das ist es sowieso nur noch mittels Compiler-Optionsschalter), sondern auch zu älteren FreeBASIC-Versionen. Allein die saubere Umsetzung von boolschen Variablen hat einige Zeit in Anspruch genommen, weil man nicht die Programme kaputt machen wollte, die in alter Manier Wahrheitswerte in Rechnungen eingebaut haben. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|