Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

Byte Streaming DataBase (Facil de utilizar)

Iniciado por kaito, Agosto 02, 2015, 10:02:53 PM

Tema anterior - Siguiente tema
Enlace de descarga: https://app.box.com/s/lvmzipqd0jsjfg55upv557gp3ed530b7 En relación con el post http://unityspain.com/topic/15864-id-única-y-constante/?preview=1" data-ipshover-timeout="1.5" itemprop="url" data-role="editableTitle" id="ips_uid_2" style="box-sizing: border-box; color: rgb(205, 56, 22); text-decoration: none; outline: 0px; font-weight: bold; line-height: 18px; background-color: rgb(250, 250, 250);" href="<___base_url___>/topic/15864-id-%C3%BAnica-y-constante/">ID única y constante, he creado una streaming database(base de datos de emision en tiempo real) que almacena cualquier tipo de datos, incluido clases serializadas, mediante bytes. La base de datos almacena los valores utilizando una ID de GameObject única ---> Nombre de la propiedad ---> Valor de la propiedad. Es decir, que un mismo GameObject(UniqueID) puede estar relacionado con varias propiedades o valores.
 Todos los datos, de cualquier tipo, son guardados en un mismo archivo tipo (.dat). Para poder ser leidos o modificados posteriormente son indexados en otro archivo tipo (.idx) donde se guarda el ID, el nombre de la propiedad y la posición del primer byte que ocupa en el archivo .dat. UTILIZACION: Creacion:- Nueva base de datos: podemos crear una base de datos vacía mediante el operador new, es decir, DBByte database = new DBByte("nameDataBase");
- Cargar base de datos: podemos cargar una base de datos existente mediante DBByte database = DBByte.Load("nameDataBase");

Get/Set valores:

- Coger valores: con el método genérico GetField<T>(ID,"nameProperty", value);
- Establecer valores: con otro método genérico SetField<T>(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 = 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).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 = (byte)characters;

   }

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

}

}
 Primer test, donde se crea una base de datos y se leen/modifican valores:
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;

}
 Segundo test, donde se carga/lee una base de datos existente:
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);

}   

}
   

Está bien. Interesante.Estaría bien implementarlo a nivel de clase, serializarla en binary y utilizar el dictionary igual para acceder a los registros.

Etiquetas: