using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; public class Cache { const int MAX_ELEMENTS = 1000; const string CACHE_DESCRIPTION_FILE = "files.dat"; const string CACHE_DATA_DIR = "data"; private string rootPath; private CacheDescription description; public Cache(string path) { rootPath = path; if (!Directory.Exists(GetDataPath())) { Directory.CreateDirectory(GetDataPath()); } LoadDescription(); CleanupDataDirectory(); } private string GetDataPath() { return rootPath + "/" + CACHE_DATA_DIR; } private void CleanupDataDirectory() { var directory = GetDataPath(); var di = new DirectoryInfo(directory); var files = di.GetFiles(); foreach (var f in files) { if (!description.path.ContainsKey(f.Name)) { File.Delete(directory + "/" + f.Name); } } } private string RandomName() { string result = ""; for (int i = 0; i < 30; i++) { int t = UnityEngine.Random.Range(0, 36); if (t < 10) result += (char)(t + '0'); else result += (char)(t - 10 + 'a'); } return result; } private void LoadDescription() { var path = rootPath + "/" + CACHE_DESCRIPTION_FILE; try { if (File.Exists(path)) { Stream openFileStream = File.OpenRead(path); BinaryFormatter deserializer = new BinaryFormatter(); description = (CacheDescription)deserializer.Deserialize(openFileStream); openFileStream.Close(); } else { description = new CacheDescription(); } } catch (Exception) { description = new CacheDescription(); } } public void Add(string path, byte[] data) { if (!description.path.ContainsKey(path)) { while (true) { var fileName = RandomName(); if (!File.Exists(GetDataPath() + "/" + fileName)) { description.path[path] = fileName; break; } } } var filePath = GetDataPath() + "/" + description.path[path]; File.WriteAllBytes(filePath, data); description.lastUse[path] = DateTime.Now; PurgeCache(); SaveDescription(); } private void SaveDescription() { var path = rootPath + "/" + CACHE_DESCRIPTION_FILE; try { BinaryFormatter serializer = new BinaryFormatter(); Stream openFileStream = File.OpenWrite(path); serializer.Serialize(openFileStream, description); openFileStream.Close(); } catch (Exception) { description = new CacheDescription(); } } private void PurgeCache() { // throw away excess elements // for now will use slow implementation while (description.path.Count >= MAX_ELEMENTS) { DateTime min = DateTime.MaxValue; string mpath = null; foreach (var kv in description.lastUse) { if (kv.Value < min) { min = kv.Value; mpath = kv.Key; } } // not found? if (mpath == null) break; try { File.Delete(GetDataPath() + "/" + description.path[mpath]); } catch (IOException) { } description.path.Remove(mpath); description.lastUse.Remove(mpath); } } public byte[] Get(string path) { if (!description.path.ContainsKey(path)) { return null; } try { description.lastUse[path] = DateTime.Now; return File.ReadAllBytes(GetDataPath() + "/" + description.path[path]); } catch (IOException) { return null; } } }