Writing to a binary file
BlitzMax Forums/BlitzMax Beginners Area/Writing to a binary file
| ||
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? |
| ||
write an int first, which denotes the length of the string, then the string itself. |
| ||
Alternatively, use WriteLine/ReadLine. |
| ||
I'm pretty sure that a string has a termination character in a binary file -- perhaps chr$(0) ? |
| ||
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 |
| ||
Read/WriteLine is the easiest way. |
| ||
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. |
| ||
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! |
| ||
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. |
| ||
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. |
| ||
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 |
| ||
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. |
| ||
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. |
| ||
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... |
| ||
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? |
| ||
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. |
| ||
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 |
| ||
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... |
| ||
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 |
| ||
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 |
| ||
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. |
| ||
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 |
| ||
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 |
| ||
Glad you finally got it sorted! :-) |
| ||
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 :) |