161 lines
3.2 KiB
C#
161 lines
3.2 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|