Unity の WWW を雑にキャッシュする
Unity の WWW
で画像のような比較的大きいデータを取得するとき、毎回データを取得しなおすのは非効率なので、
なんらかの方法でキャッシュしたい。
とりあえず雑に byte 配列をファイルに書き込んでキャッシュしたら、まあまあ良さそう な感じだった。
概要
-
WWW
結果のbytes
(型はbyte[]
)をファイルに書き込んでキャッシュする - キャッシュファイル名とリクエスト URL を 1:1 対応させて、キャッシュファイルを識別する
- キャッシュの作成や削除は、コードで明示的に行う
環境
- Unity 5.3.4p4
キャッシュの方針
- とりあえず雑に
- ファイルにキャッシュする
- リクエスト URL をキーにして、キャッシュを一意に識別する
- 時間を見て expire させたりはしない
- キャッシュを読みに行くときは、正規の URL の代わりに
file://
プロトコルの URL を読みに行く - キャッシュファイルは tmp に置いておいておいたら、いつか勝手に消えるかも
- キャッシュファイルは自分の好きなタイミングで(も)消せるように
結果
雑に作成したクラスは以下のとおり。
WWWCache.cs
using UnityEngine;
using System.IO;
public static class WWWCache
{
private static string CacheDirectory { get { return Path.Combine(Application.temporaryCachePath, "www"); } }
public static bool HasCache(string key)
{
return File.Exists(GetCacheFilePath(key));
}
public static string GetCacheURL(string key)
{
return "file://" + GetCacheFilePath(key);
}
private static string GetCacheFilePath(string key)
{
var hashCode = key.GetHashCode().ToString();
var cacheURL = Path.Combine(CacheDirectory, hashCode);
return cacheURL;
}
public static void CreateCache(string key, byte[] bytes)
{
if (!Directory.Exists(CacheDirectory))
{
Directory.CreateDirectory(CacheDirectory);
}
File.WriteAllBytes(GetCacheFilePath(key), bytes);
}
public static void ClearCache()
{
if (!Directory.Exists(CacheDirectory))
{
return;
}
Directory.Delete(CacheDirectory, true);
}
}
小さなポイントとしては、key
そのものではなくハッシュ値を使っている。
key
にリクエスト URL のようなファイルシステムのパスと競合する値を投げられても大丈夫なように。
使い方
WWWCache
を使ってキャッシュをすると、以下のようになる。key
にはリクエスト URL を使った。
同じ URL にリクエストを送ろうとした場合に、キャッシュがあればそちらを取得しに行く。
public IEnumerator SendRequest(string url)
{
var requestURL = WWWCache.HasCache(url) ? WWWCache.GetCacheURL(url) : url;
var www = new WWW(requestURL);
yield return www;
if (!string.IsNullOrEmpty(www.error))
{
yield break;
}
WWWCache.CreateCache(url, www.bytes);
}
毎回明示的にキャッシュ処理を書くのが嫌であれば、IEnumerator
を実装したクラスで WWW
を wrap してしまうとか。
まとめ・感想
-
WWW
結果のWWW#bytes
(型はbyte[]
)をファイルに書き込んでキャッシュした - キャッシュファイル名とリクエスト URL を 1:1 対応させて、キャッシュファイルを識別した
- URL はファイルシステムのパスと競合するので、
string#GetHashCode
でハッシュ値にして使った
- URL はファイルシステムのパスと競合するので、
- キャッシュの作成や削除は、コードで明示的に行った
- 削除については、一括で削除するメソッドだけ作っておいた
とりあえず雑に作ってみたが、今のところまあまあ良さそうに動いている。
ただし、レスポンスから有効期限を読み取ったりしていないので、かなり適当なキャッシュではある あと、キャッシュの読み書きの度にファイルの I/O が発生するので、爆速 とはいかない。
「有効期間は一括で 15 分のゆるふわ仕様」とかだったら、ファイルの作成時刻を読めばすぐできる気がする。