Seite 2 von 3

Re: WriteFile - ReadFile

Verfasst: 14.12.2014 20:43
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.

Re: WriteFile - ReadFile

Verfasst: 14.12.2014 20:55
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.

Re: WriteFile - ReadFile

Verfasst: 14.12.2014 21:04
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.

Re: WriteFile - ReadFile

Verfasst: 14.12.2014 21:10
von Kiffi
@es_91: #CRLF$

Re: WriteFile - ReadFile

Verfasst: 15.12.2014 15:52
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.

Re: WriteFile - ReadFile

Verfasst: 15.12.2014 16:58
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

Re: WriteFile - ReadFile

Verfasst: 15.12.2014 17:28
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.

Verfasst: 15.12.2014 17:36
von CodeCommander
~ DELETE ~

Re: WriteFile - ReadFile

Verfasst: 15.12.2014 17:44
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.

Re: WriteFile - ReadFile

Verfasst: 15.12.2014 17:59
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