WriteFile - ReadFile

Anfängerfragen zum Programmieren mit PureBasic.
es_91
Beiträge: 410
Registriert: 25.01.2011 04:48

Re: WriteFile - ReadFile

Beitrag von es_91 »

Es gibt unter PureBasic nur ReadFile () für's Lesen, OpenFile () für's Lesen und für's Schreiben und CreateFile (), was wie OpenFile () ist, nur, dass die existierende Datei überschrieben wird.

Für Dein Problem, schätze ich, benötigen wir weitere Codebeispiele!

Eine reine Übersetzung für den Binary-Mode gibt es, soweit ich weiß, nicht.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
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

Re: WriteFile - ReadFile

Beitrag von NicTheQuick »

Man muss eine Datei nicht als binary öffnen. Dateien sind immer binary. Wenn du allerdings Rohdaten schreiben willst, die direkt an einer Speicheradresse stehen, dann kannst du 'WriteData()' nehmen.
Wenn du 'WriteString()' nutzt, wird kein #CRLF$ am Ende geschrieben. Das heißt, wenn du das dann immer noch in der Datei hast, dann ist das wohl schon in deinem String drin.
es_91
Beiträge: 410
Registriert: 25.01.2011 04:48

Re: WriteFile - ReadFile

Beitrag von es_91 »

Hat er ja indirekt gesagt, dass er Zeilenumbrüche im String hat.

Code: Alles auswählen

Define file$
Define ff
Define String$

String$ = "Hallo," + #CRLF$ + "Welt!"

file$ = SaveFileRequester ("", "", "", #Null)

ff = OpenFile (#PB_Any, file$)

If ff
  
  WriteData (ff, @ String$, Len (String$))
  
  CloseFile (ff)
  
EndIf
Den Code bitte im ASCII-Modus ausführen.

@Kiffi: Whooops. :mrgreen: Bearbeitet.
Zuletzt geändert von es_91 am 14.12.2014 21:13, insgesamt 1-mal geändert.
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: WriteFile - ReadFile

Beitrag von Kiffi »

@es_91: #CRLF$
a²+b²=mc²
stevie1401
Beiträge: 700
Registriert: 19.10.2014 15:51
Kontaktdaten:

Re: WriteFile - ReadFile

Beitrag von stevie1401 »

So, nun bin ich auf der richtigen Spur:
Die Datei, die der Server sendet, ist ca. 2 MB gross.
Das scheint zu gross zu sein.
Kleinere Dateien liest der PB-Clienten fehlerlos.
Bis 94341 Byte Stringlänge empfängt der Client richtig, danach gibt es Fehler.
Am Server kann es kaum liegen, da GFA-Basic Clients problemlos Strings beliebiger Größe empfangen können.


Ich rufe mit folgendem Code Daten per Timer alle 1/100 Sec. vom Server ab:

Code: Alles auswählen


 Procedure ReadNetData()
    
    Protected Puffergroesse.l, Laenge.l, Temp.s
    Define *MemoryID 
    Puffergroesse = 8192
    *MemoryID = AllocateMemory(Puffergroesse)
    If *MemoryID
      Repeat
        Laenge = ReceiveNetworkData(ConnectionID, *MemoryID, Puffergroesse)
        Temp + PeekS(*MemoryID, Puffergroesse,#PB_Ascii)  ;es muss zwingend #PB_ASCII sein, weil die Daten vom Server im ASCII Format gesendet werden.
                                                          ;sonst bleibt es bei Umlauten hängen.
        
      Until Laenge < Puffergroesse
      FreeMemory(*MemoryID)
    EndIf
    StringFromServer=StringFromServer+temp
    
    
    
    
    
  EndProcedure


StringFromServer ist ein Globaler String
In einer anderen Procedure wird dieser String auf Nachrichten untersucht.
Ich programmiere nur noch mit Linux.
Linux Mint 21.x
Benutzeravatar
helpy
Beiträge: 636
Registriert: 29.08.2004 13:29

Re: WriteFile - ReadFile

Beitrag von helpy »

Hallo stevie1401,

Deine Netzwerkschleife:

Code: Alles auswählen

      Repeat
        Laenge = ReceiveNetworkData(ConnectionID, *MemoryID, Puffergroesse)
        Temp + PeekS(*MemoryID, Puffergroesse,#PB_Ascii)  ;es muss zwingend #PB_ASCII sein, weil die Daten vom Server im ASCII Format gesendet werden.
                                                          ;sonst bleibt es bei Umlauten hängen.
       
      Until Laenge < Puffergroesse
Damit wird das nicht gehen!
Ich sehe folgende Probleme:
  • Der Client weiß nicht, wie groß der zu empfangende String-Paket sein wird! ... oder gibt es eine bestimmte Zeichenfolge (z.B. "@@ENDE-DES-STRINGS@@"), die das String-Ende kennzeichnet?
  • Wenn Du weniger 8192 Bytres empfängst bedeutet, das noch nicht, dass wirklich alle Daten des String-Pakets angekommen sind.
  • Mit "PeekS(*MemoryID, Puffergroesse,#PB_Ascii)" liest Du zu viele Daten ein, wenn Laenge < Puffergroesse ist:
    ==> Du solltest "PeekS(*MemoryID, Laenge,#PB_Ascii)" verwenden!
Noch eine Frage:
Kannst Du sicherstellen, dass der Server nur Strings schickt, die keine "NULL-Zeichen" enthalten?
Es gibt nämlich auch Programmiersprachen, da dürfen Strings auch NULL-Zeichen als gültige Zeichen enthalten! Wenn das bei Deinem Server der Fall ist, musst Du das Empfangen anders regeln.

In PureBasic kennzeichnet ein NULL-Zeichen immer das String-Ende!

Eine endgültige Antwort ist also erst möglich, wenn genaue Informationen über das Format der gesendeten Datenpakete des Servers vorliegen.

cu,
guido
Windows 10
PB Last Final / (Sometimes testing Beta versions)
stevie1401
Beiträge: 700
Registriert: 19.10.2014 15:51
Kontaktdaten:

Re: WriteFile - ReadFile

Beitrag von stevie1401 »

Nun, eigentl. mache ich das mit dem PB-Client genauso wie ich es mit dem GFA-Basic Client mache.

Alles was reinkommt wird in den String "StringFromServer" gelegt.

In einer anderen Procedure wird nun dieser String abgefragt, ob bestimmte Inhalte in diesem String sind:
So sucht er z.B. den String nach <<karten>><</karten>> ab, um die Spielkarten des Spieler zu bekommen.
Alles was zwischen <<karten>><</karten>> ist, sind Spielkarten.
So gibt es viele Suchbegriffe, nach denen gesucht wird. Habe ich <<suchbegriff>> gefunden, muss ich nach <</suchbegriff>> suchen. Habe ich <</suchbegriff>> gefunden, habe ich die gewünschten Daten, indem ich <<suchbegriff>>String<</suchbegriff>> mir schnappe und verarbeite.
Ich habe also immer Stringanfang und Stringende.
Unter GFA-Basic funktioniert das mit Stringlängen beliebiger Größe. Es kann also ein ellenlanger String zwischen <<suchbegriff>> und <</suchbegriff>> sein.
In meinem PB Programm kommen Fehler, wenn der String zwischen <<suchbegriff>> und <</suchgebriff>> länger als 94341 Byte ist.
"NULL-Zeichen" schliesse ich aus, da ich den Server selbst programmiert habe und meine GFA-Client auch nicht damit umgehen können.
Der Fehler liegt eindeutig im PB-Client.
Ich programmiere nur noch mit Linux.
Linux Mint 21.x
Benutzeravatar
CodeCommander
Beiträge: 213
Registriert: 02.03.2014 16:06

Beitrag von CodeCommander »

~ DELETE ~
Zuletzt geändert von CodeCommander am 18.01.2015 14:55, insgesamt 1-mal geändert.
~ DELETE ~
es_91
Beiträge: 410
Registriert: 25.01.2011 04:48

Re: WriteFile - ReadFile

Beitrag von es_91 »

Wir hatten neulich das Experiment, wieviele Zeichen ein PB-String verarbeiten kann, es sind wohl so um eine Milliarde Zeichen im ASCII-Modus.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
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

Re: WriteFile - ReadFile

Beitrag von NicTheQuick »

Hier mal eine korrigierte Fassung deines Codes. Ich hoffe ich habe jetzt selbst nichts übersehen.

Code: Alles auswählen

EnableExplicit

#PUFFER_GROESE = 8192
#TIMEOUT = 1000 ;Das hier auf 0 setzen, wenn kein Timeout benutzt werden soll.

Procedure ReadNetData()
	Protected Laenge.i, Temp.s
	Protected timeout.i
	Protected *MemoryID
	
	*MemoryID = AllocateMemory(#PUFFER_GROESE)
	If *MemoryID
		Repeat
			; Starte das Timeout.
			timeout = ElapsedMilliseconds() + #TIMEOUT
			Laenge = ReceiveNetworkData(ConnectionID, *MemoryID, #PUFFER_GROESE)
			; Erst wenn auch nach dem Timeout keine Daten mehr kommen, brechen wir das Empfangen ab.
			; Allerdings bedeutet das noch nicht unbedingt, dass nicht noch etwas kommen könnte.
			; Normalerweise sollte der Server zuerst die Größe der Daten schicken und dann sollte
			; der Client so lange auf Daten warten, bis alles empfangen wurde.
			If (Laenge = 0 And ElapsedMilliseconds() >= timeout)
			 	Break
			EndIf
			; Lies nur so viele Zeichen mit PeekS aus dem Speicher wie auch empfangen wurden.
			Temp + PeekS(*MemoryID, Laenge, #PB_Ascii)
		ForEver
		FreeMemory(*MemoryID)
	EndIf
	
	StringFromServer + Temp
EndProcedure
Antworten