💬

UnityWebRequestの微妙さを改善する

2022/01/27に公開

Unityを使うならUnityWebRequestを使うってのが定石かと思うんですが、2つ気になる点があります。

  1. byte[]だと2GB以上のデータが入ってくるとデータ欠損するやないかい!
  2. awaitできへんのかい!

ということでStreamに直書きする拡張を作りました。
DownloadHandlerScriptには進捗管理の処理を省いてますが、必要なら簡単に記述できると思うんで調べてみてください(投げやり)

    internal class StreamedDownloadHandler : DownloadHandlerScript
    {
        private readonly Stream _writeStream;

        public StreamedDownloadHandler(Stream writeStream)
        {
            _writeStream = writeStream;
        }

        protected override bool ReceiveData(byte[] data, int dataLength)
        {
            _writeStream.Write(data, 0, dataLength);
            return true;
        }

        protected override void CompleteContent()
        {
            _writeStream.Flush();
            _writeStream.Seek(0, SeekOrigin.Begin);
        }
    }
    
    public static class UnityWebRequestExtensions
    {
        public static async Task WriteToStreamAsync(this UnityWebRequest request, Stream stream)
        {
            var downloadHandler = new StreamedDownloadHandler(stream);
            request.downloadHandler = downloadHandler;

            request.SendWebRequest();

            while (request.isDone == false)
            {
                // 毎フレーム確認マン
                await Task.Delay(1);
            }
        }
    }

使用はこう

        public async Task SomeMethod()
        {
            using var fileStream = File.OpenWrite(Path.Combine(Application.dataPath, "test.txt"));
            using var webRequest = new UnityWebRequest("http://www.google.com/");

            await webRequest.WriteToStreamAsync(fileStream);
        }

エラー処理とかはSomeMethodで行う想定。
必要ならCryptoStreamとか作れば暗号化しながらファイル保存したりできる。

UnityWebRequestそれ自体をStreamReaderにできそうな気もするけど考え中。

Discussion