Byte Streaming DataBase (Easy to use)

Download link.

In relation with old post UniqueID, I created a byte stream database quite easy to use it.

I can store in a file any type of values, included serialized classes.

The database organizes data from a unique GameObject ID → Name property → property value.

That is, a same GameObject (UniqueID) can be associated with several properties or values.

HOW TO USE:

To create:

a) Empty database: you can create empty database with new operator, that is, DBByte database = new DBByte(“nameDataBase”);
b) Load datase: you can load an existing database through DBByte database = DBByte.Load(“nameDataBase”);

To Get/Set values:

a) Get values with generic method GetField(ID,“nameProperty”, value);
b) Set values with other generic method SetField(ID,“nameProperty”, value);

using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;

public class DBByte {

    const byte keyLength = 20;

    public class Index{

        public int size;    //Byte size
        public long pos;     //Place in data file

        public Index(){}
        public Index(int size, long pos){

            this.size = size;
            this.pos = pos;

        }

    }

    Dictionary<uint,Dictionary<string,Index>> index;

    string idxFile, datFile;

    static byte[] Segment(byte[] array, long offSet, long length){

        byte[] temp = new byte[length];
        for(long i=0; i<length; i++) temp[i] = array[offSet + i];
        return temp;

    }

    public static DBByte Load(string nameDB){

        string idxFile = UnityEngine.Application.dataPath + "/" + nameDB + ".idx";
        string datFile = UnityEngine.Application.dataPath + "/" + nameDB + ".dat";

        if(File.Exists(idxFile) && File.Exists(datFile)){

            FileStream fsDat = new FileStream(datFile, FileMode.Open);
            FileStream fsIdx = new FileStream(idxFile, FileMode.Open);

            if(fsDat.Length == 0 || fsIdx.Length == 0){


                fsDat.Close();
                fsIdx.Close();
                UnityEngine.Debug.Log("Empty data file");
                return new DBByte(nameDB);

            }

            if(fsIdx.Length % (keyLength + 16) != 0){

                UnityEngine.Debug.Log("Idx file corrupted");
                fsDat.Close();
                fsIdx.Close();
                return new DBByte(nameDB);

            }

            DBByte loadDBByte = new DBByte();

            loadDBByte.index = new Dictionary<uint, Dictionary<string,Index>>();

            byte[] idxBytes = new byte[fsIdx.Length];
            fsIdx.Read(idxBytes, 0, (int)fsIdx.Length);
            long count = 0;

            while(count < idxBytes.LongLength){

                /*
                (ID) : 4 bytes
                (tempIndex.size) : 4 bytes;
                (tempIndex.pos) : 8 bytes;
                (field.PadRight(keyLength)) : keyLength bytes;

                Total: 16 + keyLength bytes
                */

                uint ID = BitConverter.ToUInt32(Segment(idxBytes,count,4),0);
                count += 4;
                int size = BitConverter.ToInt32(Segment(idxBytes,count,4),0);
                count += 4;
                long pos = BitConverter.ToInt64(Segment(idxBytes,count,8),0);
                count += 8;

                string field = ByteToString(Segment(idxBytes, count, keyLength));
                count += keyLength;

                if(!loadDBByte.index.ContainsKey(ID)){

                    loadDBByte.index.Add(ID, new Dictionary<string, Index>());

                }

                loadDBByte.index[ID].Add(field, new Index(size,pos));

            }

            fsDat.Close();
            fsIdx.Close();

            loadDBByte.idxFile = idxFile;
            loadDBByte.datFile = datFile;

            return loadDBByte;

        }

        return default(DBByte);

    }

    private DBByte(){}

    public DBByte(string nameDB){

        this.index = new Dictionary<uint, Dictionary<string,Index>>();
        this.idxFile = UnityEngine.Application.dataPath + "/" + nameDB + ".idx"; //Index Data
        this.datFile = UnityEngine.Application.dataPath + "/" + nameDB + ".dat"; //Byte Data

        FileStream fs = File.Create(this.idxFile);
        fs.Close();

        fs = File.Create(this.datFile);
        fs.Close();

    }

    public T GetField<T>(uint ID, string field){

        FileStream fsDat = new FileStream(this.datFile, FileMode.Open);

        field = field.PadRight(keyLength);

        if(this.index.ContainsKey(ID)){

            if(this.index[ID].ContainsKey(field)){

                Index tempIndex = this.index[ID][field];
                byte[] array = new byte[tempIndex.size];

                fsDat.Seek(tempIndex.pos, SeekOrigin.Begin);
                fsDat.Read(array, 0, tempIndex.size);

                MemoryStream ms = new MemoryStream();
                BinaryFormatter bf = new BinaryFormatter();
                ms.Write(array, 0, tempIndex.size);
                ms.Seek(0, SeekOrigin.Begin);

                T temp = (T)bf.Deserialize(ms);

                bf = null;
                tempIndex = null;
                ms.Close();
                fsDat.Close();

                return temp;

            } else UnityEngine.Debug.Log("Field " + field + " doesn't exist");

        } else UnityEngine.Debug.Log("ID " + ID + " doesn't exist");

        fsDat.Close();

        return default(T);

    }

    public bool SetField<T>(uint ID, string field, T value){

        field = field.PadRight(keyLength);

        if(this.index.ContainsKey(ID)){

            Dictionary<string,Index> tempDictionary = this.index[ID];

            if(tempDictionary.ContainsKey(field)){

                FileStream fsDat = new FileStream(this.datFile, FileMode.Open);

                //Convert to binary

                BinaryFormatter bf = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                bf.Serialize(ms,value);
                byte[] array = ms.ToArray();

                Index tempIndex = tempDictionary[field];

                if(array.Length == tempIndex.size){

                    fsDat.Seek(tempIndex.pos, SeekOrigin.Begin);
                    fsDat.Write(array, 0, array.Length);

                } else {

                    UnityEngine.Debug.Log("Length type value is different to original");
                    return false;

                }

                bf=null;
                array=null;
                tempIndex=null;
                ms.Close();
                fsDat.Close();

            } else this.AddField<T>(ID, field, value);

        } else {

            this.index.Add(ID, new Dictionary<string, Index>());
            this.AddField<T>(ID, field, value);

        }

        return true;

    }

    static string ByteToString(byte[] bytes){

        string temp = "";
        for(int i=0; i<bytes.Length; i++){

            temp += ((char)bytes[i]).ToString();

        }

        return temp;

    }

    static byte[] StringToByte(string text){

        char[] characters = text.ToCharArray();
        byte[] temp = new byte[text.Length];

        for(int i=0; i<text.Length; i++){

            temp[i] = (byte)characters[i];

        }

        return temp;

    }

    void AddField<T>(uint ID, string field, T value){

        FileStream fsDat = new FileStream(this.datFile, FileMode.Append);
        FileStream fsIdx = new FileStream(this.idxFile, FileMode.Append);
        BinaryWriter idx = new BinaryWriter(fsIdx);
    
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream ms = new MemoryStream();
        bf.Serialize(ms,value);
        byte[] array = ms.ToArray();

        Index tempIndex = new Index(array.Length, fsDat.Length);

        fsDat.Write(array,0,array.Length);

        idx.Write(ID);
        idx.Write(tempIndex.size);
        idx.Write(tempIndex.pos);
        idx.Write(StringToByte(field));

        this.index[ID].Add(field, tempIndex);
    
        ms.Close();
        idx.Close();
        fsDat.Close();
        fsIdx.Close();

    }

}

First test, where a new database is created:

using UnityEngine;
using System.Collections;

public class TestDB : MonoBehaviour {

    void Start () {     

        DBByte db = new DBByte("TestDB");

        db.SetField<float>(0,"value1",1.1f);
        db.SetField<float>(0,"value2",2.1f);
        db.SetField<bool>(0,"value3",true);
        db.SetField<float>(0,"value4",4.1f);
        db.SetField<string>(0,"value5","Text".PadRight(50));
        db.SetField<float>(0,"value6",6.1f);
        db.SetField<int>(0,"value7",-7000);

        TestClass testClass = new TestClass();

        db.SetField<TestClass>(0,"value8", testClass);

        Debug.Log("value 1: "+db.GetField<float>(0,"value1"));
        Debug.Log("value 2: "+db.GetField<float>(0,"value2"));
        Debug.Log("value 3: "+db.GetField<bool>(0,"value3"));
        Debug.Log("value 4: "+db.GetField<float>(0,"value4"));
        Debug.Log("value 5: "+db.GetField<string>(0,"value5"));
        Debug.Log("value 6: "+db.GetField<float>(0,"value6"));
        Debug.Log("value 7: "+db.GetField<int>(0,"value7"));

        TestClass tempTestClass = db.GetField<TestClass>(0,"value8");

        Debug.Log("value 8: " + tempTestClass.intValue+" - " + tempTestClass.bValue);

        testClass.intValue = 11111;
        testClass.bValue = !testClass.bValue;

        db.SetField<TestClass>(0,"value8", testClass);

        db.SetField<float>(0,"value2",12.2f);
        db.SetField<bool>(0,"value3",false);
        db.SetField<float>(0,"value4",14.2f);
        db.SetField<string>(0,"value5","Second Text".PadRight(50));
        db.SetField<float>(0,"value6",16.2f);
        db.SetField<int>(0,"value7",15000);

        Debug.Log("-------------------------");

        Debug.Log("value 1: "+db.GetField<float>(0,"value1"));
        Debug.Log("value 2: "+db.GetField<float>(0,"value2"));
        Debug.Log("value 3: "+db.GetField<bool>(0,"value3"));
        Debug.Log("value 4: "+db.GetField<float>(0,"value4"));
        Debug.Log("value 5: "+db.GetField<string>(0,"value5"));
        Debug.Log("value 6: "+db.GetField<float>(0,"value6"));
        Debug.Log("value 7: "+db.GetField<int>(0,"value7"));

        tempTestClass = db.GetField<TestClass>(0,"value8");
    
        Debug.Log("value 8: " + tempTestClass.intValue+" - " + tempTestClass.bValue);

    }

}

[System.Serializable]
public class TestClass{

    public int intValue = 1;
    public bool bValue = true;

}

Second test, where a database is loaded.

using UnityEngine;
using System.Collections;

public class LoadDB : MonoBehaviour {

    void Start () {

        DBByte db = DBByte.Load("TestDB");

        Debug.Log("value 1: " + db.GetField<float> (0,"value1"));
        Debug.Log("value 2: " + db.GetField<float> (0,"value2"));
        Debug.Log("value 3: " + db.GetField<bool>  (0,"value3"));
        Debug.Log("value 4: " + db.GetField<float> (0,"value4"));
        Debug.Log("value 5: " + db.GetField<string>(0,"value5"));
        Debug.Log("value 6: " + db.GetField<float> (0,"value6"));
        Debug.Log("value 7: " + db.GetField<int>   (0,"value7"));

        TestClass tempTestClass = db.GetField<TestClass>(0,"value8");

        Debug.Log("value 8: " + tempTestClass.intValue + " - " + tempTestClass.bValue);

    }

}

Does this work for Textures 2???..

You can use Texture methods GetPixels or GetPixels32, that return an array.

1 Like