C# 在Unity中使用协程更新进度条时读取文件

C# 在Unity中使用协程更新进度条时读取文件,c#,unity3d,stream,coroutine,C#,Unity3d,Stream,Coroutine,我试图在更新进度条时逐行读取文件(两个GUI纹理,其中一个宽度(maxWidth*currentPercentage)带有浮点扩展) 我有两个实现: public static string ThreadedFileRead(string path, Action<float> percAction) { FileInfo fileInfo = new FileInfo(path); StringBuilder sb = new Str

我试图在更新进度条时逐行读取文件(两个GUI纹理,其中一个宽度(maxWidth*currentPercentage)带有浮点扩展)

我有两个实现:

    public static string ThreadedFileRead(string path, Action<float> percAction)
    {
        FileInfo fileInfo = new FileInfo(path);
        StringBuilder sb = new StringBuilder();

        float length = fileInfo.Length;
        int currentLength = 0;

        using (StreamReader sr = new StreamReader(path))
        {
            while (!sr.EndOfStream)
            {
                string str = sr.ReadLine();
                sb.AppendLine(str);

                // yield return str;

                percAction(currentLength / length);
                currentLength += str.Length;
                Interlocked.Add(ref currentLength, str.Length);
            }

            percAction(1f);

            return sb.ToString();
        }
    }
publicstaticstringthreadedfileread(字符串路径,Action peraction)
{
FileInfo FileInfo=新的FileInfo(路径);
StringBuilder sb=新的StringBuilder();
float length=fileInfo.length;
int currentLength=0;
使用(StreamReader sr=新StreamReader(路径))
{
而(!sr.EndOfStream)
{
字符串str=sr.ReadLine();
附肢线(str);
//收益率;
PERACTION(当前长度/长度);
当前长度+=长度;
联锁。添加(参考当前长度、str.Length);
}
peraction(1f);
使某人返回字符串();
}
}
使用以下实现:

  // Inside a MonoBehaviour

  public void Start() 
  {
       string fileContents = "";
       StartCoroutine(LoadFileAsync(Application.dataPath + "/Data/file.txt", (s) => fileContents = s));
  }

  public IEnumerator LoadFileAsync(string path, Action<string> fin) 
  {
        string contents = "";

        lock (contents)
        {
            var task = Task.Factory.StartNew(() =>
            {
                contents = F.ThreadedFileRead(path, (f) => currentLoadProgress = f);
            });

            while (!task.IsCompleted)
                yield return new WaitForEndOfFrame();

            fin?.Invoke(contents);
        }
  }
  public IEnumerator LoadFileAsync(string path, Action<string> fin) 
  {
       yield return F.LoadFileAsync(path, (f) => currentLoadProgress = f, fin);
  }
//在一个单一行为中
公开作废开始()
{
字符串fileContents=“”;
start例程(LoadFileAsync(Application.dataPath+“/Data/file.txt”,(s)=>fileContents=s));
}
公共IEnumerator LoadFileAsync(字符串路径,操作fin)
{
字符串内容=”;
锁(内容)
{
var task=task.Factory.StartNew(()=>
{
contents=F.ThreadedFileRead(路径,(F)=>currentLoadProgress=F);
});
而(!task.IsCompleted)
返回新的WaitForEndOfFrame();
fin?调用(内容);
}
}
但是这会阻塞当前的GUI(我不知道为什么)

我也用了这个:

    // Thanks to: https://stackoverflow.com/questions/41296957/wait-while-file-load-in-unity
    // Thanks to: https://stackoverflow.com/a/34378847/3286975
    [MustBeReviewed]
    public static IEnumerator LoadFileAsync(string pathOrUrl, Action<float> updatePerc, Action<string> finishedReading)
    {
        FileInfo fileInfo = new FileInfo(pathOrUrl);

        float length = fileInfo.Length;

        // Application.isEditor && ??? // Must review
        if (Path.IsPathRooted(pathOrUrl))
            pathOrUrl = "file:///" + pathOrUrl;

        /*

        using (var www = new UnityWebRequest(pathOrUrl))
        {
            www.downloadHandler = new DownloadHandlerBuffer();

            CityBenchmarkData.StartBenchmark(CityBenchmark.SendWebRequest);

            yield return www.SendWebRequest();

            CityBenchmarkData.StopBenchmark(CityBenchmark.SendWebRequest);

            while (!www.isDone)
            {
                // www.downloadProgress
                updatePerc?.Invoke(www.downloadedBytes / length); // currentLength / length
                yield return new WaitForEndOfFrame();
            }

            finishedReading?.Invoke(www.downloadHandler.text);
        }

         */

        using (var www = new WWW(pathOrUrl))
        {
            while (!www.isDone)
            {
                // www.downloadProgress
                updatePerc?.Invoke(www.bytesDownloaded / length); // currentLength / length
                yield return new WaitForEndOfFrame();
            }

            finishedReading?.Invoke(www.text);
        }
    }
//多亏了:https://stackoverflow.com/questions/41296957/wait-while-file-load-in-unity
//感谢:https://stackoverflow.com/a/34378847/3286975
[必须查看]
公共静态IEnumerator LoadFileAsync(字符串pathrUrl、操作updatePerc、操作finisheFearding)
{
FileInfo FileInfo=新的FileInfo(pathrurl);
float length=fileInfo.length;
//Application.isEditor&&???//必须审核
if(Path.IsPathRooted(pathrurl))
pathrurl=“文件://”+pathrurl;
/*
使用(var www=new UnityWebRequest(pathrurl))
{
www.downloadHandler=new DownloadHandlerBuffer();
CityBenchmarkData.StartBenchmark(CityBenchmark.SendWebRequest);
返回www.SendWebRequest();
CityBenchmarkData.StopBenchmark(CityBenchmark.SendWebRequest);
而(!www.isDone)
{
//www.downloadProgress
updatePerc?.Invoke(www.downloaddedbytes/length);//currentLength/length
返回新的WaitForEndOfFrame();
}
FinisheFearding?.Invoke(www.downloadHandler.text);
}
*/
使用(var www=new www(pathrurl))
{
而(!www.isDone)
{
//www.downloadProgress
updatePerc?.Invoke(www.bytesloadded/length);//currentLength/length
返回新的WaitForEndOfFrame();
}
完成恐惧?.Invoke(www.text);
}
}
通过以下实施:

  // Inside a MonoBehaviour

  public void Start() 
  {
       string fileContents = "";
       StartCoroutine(LoadFileAsync(Application.dataPath + "/Data/file.txt", (s) => fileContents = s));
  }

  public IEnumerator LoadFileAsync(string path, Action<string> fin) 
  {
        string contents = "";

        lock (contents)
        {
            var task = Task.Factory.StartNew(() =>
            {
                contents = F.ThreadedFileRead(path, (f) => currentLoadProgress = f);
            });

            while (!task.IsCompleted)
                yield return new WaitForEndOfFrame();

            fin?.Invoke(contents);
        }
  }
  public IEnumerator LoadFileAsync(string path, Action<string> fin) 
  {
       yield return F.LoadFileAsync(path, (f) => currentLoadProgress = f, fin);
  }
公共IEnumerator LoadFileAsync(字符串路径,操作fin) { 产生返回F.LoadFileAsync(路径,(F)=>currentLoadProgress=F,fin); } 我共享的最后一段代码有两部分:

  • 注释部分也会阻塞主线程
  • 我使用的WWW类(将来会被弃用)不会阻止主线程,但它只在进度条上显示两个步骤(比如25%和70%)
我不知道为什么会发生这种情况,也不知道是否有更好的方法

因此,欢迎对此提供任何帮助(指导)

注释部分也会阻塞主线程

它不是“阻塞”主线程。如果它阻塞了主线程,编辑器也会冻结,直到加载或下载完成。它只是在等待
www.SendWebRequest()
完成,而在等待过程中,项目中的其他脚本仍在正常运行,并且每一帧都在运行

问题是,有些人不知道如何使用www.isDone以及何时使用它。一个例子是post,当人们发现这样的代码时,就会遇到问题

使用UnityWebRequest的两种方法:

ThreadedFileRead(path, (percent) =>
{
    Debug.Log("Update: " + percent);
}, (result) =>
{
    Debug.Log("Done: " + result);
});
1。下载或提出请求,然后忘记它,直到它完成。当您不需要知道下载的状态时,可以执行此操作,例如
UnityWebRequest.downloadedBytes
UnityWebRequest.uploadedBytes
UnityWebRequest.DownloadeProgress
UnityWebRequest.UploadeProgress

为此,您可以使用
yield return
关键字生成
UnityWebRequest.SendWebRequest()
函数。它将等待
UnityWebRequest.SendWebRequest()
函数,直到下载完成,但不会阻止您的程序。
Update
函数和其他脚本中的代码应仍在运行。该等待仅在
LoadFileAsync
coroutine函数中完成

示例(请注意使用
yield return www.SendWebRequest()
no
UnityWebRequest.isDone
):

2。下载或发出请求,然后等待每一帧,直到
UnityWebRequest.isDone
true
。当您需要了解下载的状态时,如
UnityWebRequest.downloadedBytes
UnityWebRequest.uploadedBytes
UnityWebRequest.DownloadeProgress
UnityWebRequest.UploadeProgress
v
ThreadedFileRead(path, (percent) =>
{
    Debug.Log("Update: " + percent);
}, (result) =>
{
    Debug.Log("Done: " + result);
});