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);
}
}