New File System (real files, Large files faster)

Monkey Forums/Monkey Code/New File System (real files, Large files faster)

Cygnus(Posted 2012) [#1]
This allows you to write to files in the actual filesystem (GLFW only)
It also reads files like you were used to in BlitzMax. (all platforms)

file size is not limited to the ~300k limit that seemed to be imposed by previous options.

This is based off GfKs FileSystem but uses real files, rather than a virtual file system. As such, saving files in HTML5 is not possible.
Reading files in HTML5 is possible.

Code to write to output folders is based on GreyAlien's work.

THINGS TO NOTE:

It will write files to the executables .data folder.

It also saves the same data to the current project folder by default. Disable this if you are using it in a release.

set APP_NAME to the name of the folder your files are in. (for me it was basicgame.data, hence basicgame)

Thanks to GfK and GreyAlien!

[monkeycode]
Strict
Import mojo
Import os
Const APP_NAME:String="basicgame"
Const COPY_TO_PROJECT_DATA_FOLDER:Bool=True

Class FileStream Extends DataConversion
Field filename:String
Field fileptr:Int
Private
Field arrayPointer:int
Field data:String
Field WriteData:String
Field readingOnly:bool
Public



Function WriteFile:FileStream(filename:String)
Local f:FileStream = New FileStream
f.filename = filename
f.fileptr = 0
f.arrayPointer=0
f.data=""
f.readingOnly=False
Return f
End

Function ReadFile:FileStream(filename:String)
Local f:FileStream = New FileStream
f.filename = filename
f.fileptr = 0
Print "Reading from "+filename
f.data = app.LoadString(filename) 'LoadState()
f.readingOnly=True
Return f
End

Method Close:Void()
If (readingOnly=False) Then
FlushData()
Print "Writing "+Self.WriteData.Length()+" bytes."
#If TARGET="glfw" Then

SaveString(Self.WriteData,CurrentDir()+"/data/"+filename) 'local to build - Runtime folder.
If (COPY_TO_PROJECT_DATA_FOLDER) Then
Print "Writing "+CurrentDir()+"/../../../../"+APP_NAME+".data/"+filename
SaveString(Self.WriteData,CurrentDir()+"/../../../../"+APP_NAME+".data/"+filename) 'project data path
Endif
#End
Self.data=""
Self.WriteData=""
Endif
End



Method ReadInt:Int()
Local result:String
result = Self.data[Self.fileptr..Self.fileptr+4]
Self.fileptr+=4
Return Self.StringToInt(result)
End

Method WriteInt:Void(val:Int)
' Print(val+" Outputted.")
Self.fileptr+=4
Self.data+=Self.IntToString(val)
End

Method ReadString:String()
Local result:String
Local strLen:Int = Self.StringToInt(Self.data[Self.fileptr..Self.fileptr+4])
Self.fileptr+=4
If strLen > 0
result = Self.data[Self.fileptr..Self.fileptr+strLen]
Self.fileptr+=strLen
End
Return result
End

Method WriteString:Void(val:String)
Self.data+=Self.IntToString(val.Length())
If val.Length() > 0
Self.data+=val
Self.fileptr+=val.Length()
End
CheckDataLength()
End

Method ReadFloat:Float()
Local result:Float
Local s:String
Local strLen:Int = Self.StringToInt(Self.data[Self.fileptr..Self.fileptr+4])
Self.fileptr+=4
s = Self.data[Self.fileptr..Self.fileptr+strLen]
result = Self.StringToFloat(s)
Self.fileptr+=strLen
Return result
End

Method WriteFloat:Void(val:Float)
Local s:String = Self.FloatToString(val)
Self.data+=Self.IntToString(s.Length())
Self.data+=s
CheckDataLength()

End

Method ReadBool:Bool()
Local result:Bool
result = Bool(Self.data[Self.fileptr])
Self.fileptr+=1
Return result
End Method

Method WriteBool:Void(val:Bool)
Self.data+=String.FromChar(val)
CheckDataLength()

End Method


Method ReadByte:Int()
Local result:Int= Int(Self.data[Self.fileptr])
Self.fileptr+=1
Return (result)
End

Method WriteByte:Void(val:Int)
Self.fileptr+=1
Self.data+=String.FromChar(val & $ff)'Self.ByteToString(val)
CheckDataLength()
End
Method CheckDataLength:void()
If (Self.data.Length()>65536) Then '64k round-up
Print "Flushed."
FlushData()
Endif
End Method
Method FlushData:void()
Self.WriteData=Self.WriteData+Self.data
Self.data=""
End method
End

Class DataConversion
Method IntToString:String(val:Int)
Local result:String= String.FromChar((val) & $FF)
result+= String.FromChar((val Shr 8) & $FF)
result+= String.FromChar((val Shr 16) & $FF)
result+= String.FromChar((val Shr 24) & $FF)
Return result
End

Method FloatToString:String(val:Float)
Return String(val)
End

Method StringToInt:Int(val:String)
Local result:Int
result = (val[0])
result|= (val[1] Shl 8)
result|= (val[2] Shl 16)
result|= (val[3] Shl 24)
Return result
End

Method StringToFloat:Float(val:String)
Return Float(val)
End
End
[/monkeycode]

example of use:

[monkeycode]
Local stream:FileStream=FileStream.WriteFile("Temp.dat")
stream.WriteByte(65)
stream.WriteByte(66)
stream.WriteByte(67)
stream.WriteByte(68)
stream.WriteByte(69)
stream.WriteByte(70)
stream.Close()

stream=FileStream.ReadFile("Temp.dat")
Print stream.ReadByte()
Print stream.ReadByte()
Print stream.ReadByte()
Print stream.ReadByte()
Print stream.ReadByte()
Print stream.ReadByte()
stream.Close()
[/monkeycode]


Paul - Taiphoz(Posted 2012) [#2]
use [ monkeycode ] for your code box's will make it look better.


Nobuyuki(Posted 2012) [#3]
nice, dude. Can we use something like this for direct saving/loading of tilemap data? (With the proper file filter directive, of course)


Cygnus(Posted 2012) [#4]
Yes you can, but be careful if you release to HTML5- Some browsers struggle to load data files. I'm going to add Base64 (or for speed, base52) encoding to the library shortly to allow for easy HTML5 deployment.