Writing to a binary file

BlitzMax Forums/BlitzMax Beginners Area/Writing to a binary file

Arabia(Posted 2011) [#1]
I've looked and can't find the answer :(

When writing to a binary file, I know about WriteFloat, Write Int etc.

But when reading them back, you really need to know how long a string is.

Can you define a String as being a fixed length? I'm sure I've seen it done in a tutorial but for the life of me I can't find it. Without this it's impossible to save a string into a binary file is it not?


GfK(Posted 2011) [#2]
write an int first, which denotes the length of the string, then the string itself.


Oddball(Posted 2011) [#3]
Alternatively, use WriteLine/ReadLine.


xlsior(Posted 2011) [#4]
I'm pretty sure that a string has a termination character in a binary file -- perhaps chr$(0) ?


Oddball(Posted 2011) [#5]
It's new line/null terminated if you use WriteLine/ReadLine, but not if you use WriteString/ReadString which needs to know the strings length. Hence my suggestion.

Last edited 2011


Czar Flavius(Posted 2011) [#6]
Read/WriteLine is the easiest way.


Arabia(Posted 2011) [#7]
Thanks. I'll have a play around with both suggestions (using an int to show string length) and also writeline/readline.

My other preferred option is using an Access Database (yes I know) or SQL lite Database. I've read a bit about both of these - requires a Brucey MOD? but most of it currently goes right over my head.


Czar Flavius(Posted 2011) [#8]
I tried SQL once but it was more trouble than it's worth. If it's just for general game data files, XML is very good. Easy to program, design and also edit by hand if needed.

<level num="1"> <player num="1" name="Bob" lives="3" ammo="10" /> </level>
Whatever!


Arabia(Posted 2011) [#9]
It's actually for a cricket game I'm trying to write. A database really is the best approach since there could be hundreds of players in the database and it would be useful to have sort capabilities on several different columns.

I know you can do this with XML, just a matter of reading the file and grabbing what you want etc, but if I remember my SQL correctly (and I probably don't), it allows you to easily do something like:

SELECT * FROM PlayerTable WHERE HighScore => 100 SORT BY ASC HighScore;

It's just a matter of stepping through the resulting rows and displaying the data etc.


xlsior(Posted 2011) [#10]
I recommend you take a look at SQLite -- there are several SQLite modules for blitzmax, that allow you to easily store data and run queries like that from a single flat file, without the need of any other installed database engines or the likes.

Brucey's bah.sqlite module is pretty easy to use, no idea about how well the others work.


Zethrax(Posted 2011) [#11]
Here's some Purebasic code that I use for writing and reading Blitz3D style strings consisting of a length header followed by the string data. It's heavily commented, so it should be possible to convert it to BlitzMax code.

Note that in Purebasic the @ character is used to return the memory location of the string it is placed in front of.

Procedure WriteDataString( file, data_string.s )
	; NOTES: Writes out the string data in the 'data_string.s' parameter with an integer length header at the start.
	; The file should already be opened for writing with its file ID specified in the 'file' parameter.
	Protected size ; Set local variables.
	size = Len( data_string.s ) ; Obtain the size of the string to use as the length header.
	WriteLong( file, size ) ; Write out the length header.
	WriteData( file, @data_string.s, size ) ; Write out the main string data.
EndProcedure

Procedure.s ReadDataString( file )
	; NOTES: Reads in string data which has an integer length header at the start.
	; The string data should have been written out using 'WriteDataString()'.
	; The file should already be opened for reading with its file ID specified in the 'file' parameter.
	Protected size, data_string.s ; Set local variables.
	size = ReadLong( file ) ; Read in the length header.
	data_string.s = Space( size ) ; Create a string filled with the specified number of space characters.
	ReadData( file, @data_string.s, size ) ; Read in the main string data.
	ProcedureReturn data_string.s ; Return the string that was read in.
EndProcedure



Arabia(Posted 2011) [#12]
Thanks Bill. I'll try and take a look at the code you posted tonight.

I've already downloaded SQLite and had a very quick play - I've forgotten so much of the SQL I learnt 20+ years ago, will have to find a good tutorial site on SQL - Do you know of any? The SQLite site has command reference, but I learn better from tutorials that I can try out.

Don't need anything too complex, just creating tables, running fairly basic queries.

Without going into your code or Brucey's MODs - from what I've seen you can just make your database with SQLite and then call it from a command line. I'm guessing you just pipe the results to a text file and read it from there?

Downloading MySQL now also to have a quick look, but I think it's possibly more than I need. But they do seem to have a GUI available which I find easier (like MS-Access I assume) rather than having to type all of the create table commands etc.


xlsior(Posted 2011) [#13]
Without going into your code or Brucey's MODs - from what I've seen you can just make your database with SQLite and then call it from a command line. I'm guessing you just pipe the results to a text file and read it from there?


No, you can call the SQLite statements straight from your code, and it will populate a string or array with the results.

You can do it all stright from within blitzmax: create a table, modify a table, store data, and run semi-complex SQL queries on the stored data.

Here's one of Brucey's SQLite sample files:

SuperStrict

Framework BaH.DBSQLite
Import BRL.filesystem

DeleteFile("maxtest.db")

Local db:TDBConnection = LoadDatabase("SQLITE", "maxtest.db")

If Not db Then
	DebugLog("Didn't work...")
	End
End If

Local names:String[][] = [ ..
	[ "Alfred", "Aho" ],   ..
	[ "Brian", "Kernighan" ], ..
	[ "Peter", "Weinberger" ] ]

If db.isOpen() Then

	Local s:String = "CREATE TABLE person (id integer primary key AUTOINCREMENT, " + ..
	  " forename varchar(30)," + ..
	  " surname varchar(30) )"

	db.executeQuery(s)

	If db.hasError() Then
		errorAndClose(db)
	End If
	
	' transaction test :-)
	db.StartTransaction()

	If db.hasError() Then
		errorAndClose(db)
	End If

	For Local i:Int = 0 Until names.length
		db.executeQuery("INSERT INTO person values (NULL, '" + names[i][0] + "', '" + names[i][1] + "')")
		If db.hasError() Then
			errorAndClose(db)
		End If
		
	Next
	
	' commit our changes :-)
	db.Commit()

	If db.hasError() Then
		errorAndClose(db)
	End If

	Local query:TDatabaseQuery = db.executeQuery("SELECT * from person")
	If db.hasError() Then
		errorAndClose(db)
	End If

	While query.nextRow()
		Local record:TQueryRecord = query.rowRecord()
		
		DebugLog("Name = " + TDBString(record.value(1)).value + " " + TDBString(record.value(2)).value)
	Wend
	
			
	db.close()
	
End If

Function errorAndClose(db:TDBConnection)
	DebugLog(db.error().toString())
	db.close()
	End
End Function


It creates a database file, creates a table, populates it with some records, and run a query against the database to return the results.

If you already have an existing SQLite database you can interface with that as well, but it's possible to do the entire thing from within blitz.


Brucey(Posted 2011) [#14]
I tried SQL once but it was more trouble than it's worth.

Heh! To learn, or to use?

If you have lots of stats data, it's much easier to retrieve it interactively from a database. Imagine you are displaying a table with header. Clicking on a particular column header you can re-retrieve the data simply by changing the "ORDER BY" column of the SQL. Coding by hand would require considerably more effort.

For very large, growing datasets, it is probably better to use a database than your own custom file storage - if not least so that you don't have to worry about having to iron out bugs in it. Productions databases have had many thousands of man-hours devoted to making them work...

For a game, SQLite is probably better than MySQL, although there's no reason you can't develop using MySQL and migrate the data later to SQLite.
My database framework makes this as relatively/moderately painless as possible. (for basic ANSI standard queries, it might only involve a simple change of the driver, for example).

from what I've seen you can just make your database with SQLite and then call it from a command line. I'm guessing you just pipe the results to a text file and read it from there?


As xlsior points out, it's much easier to access the database directly via code than relying on external files and pipes.

they do seem to have a GUI available which I find easier

There's also a GUI for SQLite, called SQLiteBrowser, which is open source. There may be others too...


Arabia(Posted 2011) [#15]
Thanks xlsior.

I'm in the process now of installing Brucey's mod for SQLite, MinGW etc.

I've downloaded the SQLiteMod and Database Mod files as instructed by his webite. I've made a directory off blitzmax/mod called BaH.mod and unzipped the files in there.

I downloaded and installed MinGW as per the instructions in a thread by Ziggy.

I've rebuilt the docs and now have access to them in MaxIDE. The "Build Modules" option is now available to me. When I click on it, I get :


Building Modules
Compiling:blitz_app.c
Build Error: failed to compile C:/BlitzMax/mod/brl.mod/blitz.mod/blitz_app.c
Process complete


Any ideas what I'm doing wrong?


Brucey(Posted 2011) [#16]
Your MinGW is not configure properly.

Make sure you also add the MinGW path to the environment.
You can check this by opening cmd.exe and typing gcc at the prompt. eg.
C:\BlitzMax\bin>gcc
gcc: no input files

If it reports that gcc doesn't exist, your PATH is incomplete.


Arabia(Posted 2011) [#17]
Cheers Brucey, I found some SQLite GUI's. Just trying to get your mods working and I'll download one and then start playing with code to retrieve data from the SQLite DB


Brucey(Posted 2011) [#18]
Part 3 in Ziggy's little guide :

3.- In the 'System Variables' box, scroll down until you see the variables Path. Click on it and click the edit button. In the 'Variable Value' box, move your curser to the end of text, ADD A SEMI COLON, and put the path to your MinGW\bin directory. eg, c:\MinGW\Bin. Click ok and ok again and if you are using windows XP, you are ready to go...




Arabia(Posted 2011) [#19]
Your MinGW is not configure properly.

Make sure you also add the MinGW path to the environment.
You can check this by opening cmd.exe and typing gcc at the prompt. eg.
C:\BlitzMax\bin>gcc
gcc: no input files

If it reports that gcc doesn't exist, your PATH is incomplete.



I've looked in C:\blitzmax\bin and there is no GCC.EXE. I take it I download this and put it in the bin directory? I'm on the GCC.GNU.ORG site and not exactly sure what I'm supposed to download/install :S


Arabia(Posted 2011) [#20]
Yep, done part 3 successfully already Brucey.

Using Win 7 if that makes any difference - I did follow the steps in Ziggy's thread - I might just go back in and double checking spelling etc.

Last edited 2011


Brucey(Posted 2011) [#21]
I've looked in C:\blitzmax\bin and there is no GCC.EXE. I take it I download this and put it in the bin directory?

No. Everything you need is installed with MinGW (compiler, headers, libs, etc).
If your environment is correct, running "gcc" from a command line should work. If it is not found, your path is wrong.


Arabia(Posted 2011) [#22]
Thanks for the help Brucey. My stupid mistake.

I didn't look closely enough when unRar'ing the MinGW file. It's already packaged inside of a folder called "MinGW" and I told it to unRar to "c:\MinGW" which of course put it into "c:\minGW\minGW\"

Just rebuilt the modules and all went okay. Going to have a quick play with your example files now :)

Thanks.

Last edited 2011


Arabia(Posted 2011) [#23]
Just tried the first test_01.bmx file with the SQLite mod and it works :) Will have a bit of a read of the code tonight to make sure I know what is going on :) Will have to spend some time on the weekend re-educating myself on SQL syntax :)

Thanks for the help :D


Brucey(Posted 2011) [#24]
Glad you finally got it sorted!

:-)


Arabia(Posted 2011) [#25]
First time I've tried installing one of your mods Brucey. I'll look at more of them now that I'm less scared about the installation process :)