Search Unity

Check if StreamWriter sw isFinished

Discussion in 'Scripting' started by UnityFuchs, Jul 27, 2020.

  1. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    Hi everyone,
    I have a problem with my StreamWriter.

    Explanation: I have a data.txt in my resources-folder and I write metadata in it. Then I upload the data.txt file to my server. The problem is, that my program uploads the data.txt first and changes the text in it later. Bad timing?

    I call the create-function and the upload-function with one button at the same time.

    I tried several debugs, but everything looks fine to me. I can't figure out what is wrong.
    Maybe there is a function that I can call which shows me when my StreamWriter is finished with writing.

    Code (CSharp):
    1. //This is where I save my data during runtime. This works fine.
    2. public static class Values
    3. {
    4.     public static string user_code;
    5. }
    Code (CSharp):
    1. public class CreateMetaFile : MonoBehaviour
    2. {
    3. using (StreamWriter sw = new StreamWriter("Assets/Resources/data.txt"))
    4.         {
    5.             //Add my string to the file.
    6.             sw.Write(str);
    7.         }
    8.         //Every output shows: str == Values.user_code, so that is fine.
    9.  
    10.         //A StreamReader for testing shows the same result.
    11. using (StreamReader sr = new StreamReader("Assets/Resources/data.txt"))
    12.         {
    13.             string line = sr.ReadLine();
    14.             if (line == str)
    15.                 isReady = true;
    16.         }
    17.         //That means, at this point, the data should be written. The next step is, to get the isReady : bool and upload my file.
    18. }
    Code (CSharp):
    1. //I try to ask if the file is written, to be absolutely sure.
    2. IEnumerator Upload_DataFile()
    3.     {
    4.         yield return new WaitUntil(() => CheckMetaData() == true);
    5.     }
    6.  
    7.     private bool CheckMetaData()
    8.     {
    9.         if (this.GetComponent<CreateMetaFile>().isReady)
    10.         {
    11.             Debug.Log("MetaData is written.");
    12.             return true;
    13.         }
    14.         else
    15.         {
    16.             Debug.Log("Waiting for MetaData to be written.");
    17.             return false;
    18.         }
    19.     }
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    I'm not clear on exactly what the problem is here. Can you elaborate? What is going wrong? What are you expecting to happen and what is happening instead?
     
  3. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    1. I have a data.txt
    2. data.txt has content: "my_fist_content"
    3. On runtime, I change the content with: "my_second_content"
    4. Then I upload the data.txt to my server.
    5. I open my data.txt on the server and expect "my_second_content", but it is "my_first_content".
    6. If I do the same again and change my content to: "my_third_content", then tha data.txt, will have "my_second_content".

    That means, that my program uploads my data.txt first and writes the new content second, which is bad.
    My program should write the new content first and then, if everything is wrote, upload second.
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Can you share your uploading code?
     
  5. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    Ok, I constrained my errors. The problem is, that the Streamwriter won't update early enough or won't write properly.
    I tried to manually flush and close this buddy but he stays riot.

    Code (CSharp):
    1.     public void CreateMyTextFile()
    2.     {
    3.         str += Values.user_code;
    4.  
    5.         for(int i = 0; i < Values.my_images.Count; i++)
    6.         {
    7.             Create_My_String(i);
    8.         }
    9.  
    10.         using (StreamWriter streamWriter = new StreamWriter("Assets/Resources/data.txt"))
    11.         {
    12.             //Add my string to the file.
    13.             streamWriter.Write(str);
    14.             print("my str: " + str);
    15.  
    16.             streamWriter.Flush();
    17.             streamWriter.Close();
    18.  
    19.             isReady = true;
    20.         }
    21.  
    22.         print("did it wrote?: " + Resources.Load<TextAsset>("data").ToString());
    23.     }
     
  6. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    This is kind of stupid. The text in data.txt only changes if I refresh the textfile. After the refresh, everything works fine. Where is the error?
     
  7. WarmedxMints

    WarmedxMints

    Joined:
    Feb 6, 2017
    Posts:
    1,035
    Load the file directly, don't go via Unity resources as they don't update in editor play mode unless you force them too. You'll want to be writing and reading a text file directly in a build anyway unless you don't plan on modifying it once built.
     
  8. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    Thx for the answer. I need to change the text in that textfile and upload it. That means i need to look after the Resources-Update thing. There should be another solution... create TextAsset at runtime, and upload it. This should work am I right?
     
    Last edited: Jul 29, 2020
  9. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    I made it work, kind of a force. Can't find a better solution and get a error, but it works.
    Code (CSharp):
    1.     public void CreateMyTextFile()
    2.     {
    3.         str += Values.user_code;
    4.  
    5.         for(int i = 0; i < Values.my_images.Count; i++)
    6.         {
    7.             Create_My_String(i);
    8.         }
    9.  
    10.         TextAsset textAsset = new TextAsset();
    11.         AssetDatabase.Refresh(); //Error: Failed to load '.../Resources/data.txt'. File may be corrupted or was serialized with a newer version of Unity.
    12.         AssetDatabase.CreateAsset(textAsset, "Assets/Resources/data.txt");
    13.        
    14.         StreamWriter sw = new StreamWriter("Assets/Resources/data.txt");
    15.         sw.WriteLine(str);
    16.         sw.Close();
    17.         AssetDatabase.SaveAssets();
    18.         AssetDatabase.Refresh();
    19.  
    20.         StreamReader sr = new StreamReader("Assets/Resources/data.txt");
    21.         string line = sr.ReadLine();
    22.         sr.Close();
    23.  
    24.         //Compare the line only, because there is a "Enter" at the end of the data.txt, that I don't want.
    25.         if (line == str)
    26.         {
    27.             print("isReady = true");
    28.             isReady = true;
    29.         }
    30.         else
    31.         {
    32.             print("isReady = false");
    33.         }
    34.     }
     
  10. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Asset database stuff isn't going to work when you try to build your game. It's an editor only namespace.

    Your problem is that you're mixing up text files and text assets. They're not the same thing and it's not really supported to modify assets at runtime. As @WarmedxMints implied, just use a plain old text file. Write the initial file to Application.persistentDataPath, and continue to read/write the file from there. You can use a text asset as the initial template for the file if you want. After that though, forget about "assets" and just work with plain old files.
     
    Suddoha likes this.
  11. UnityFuchs

    UnityFuchs

    Joined:
    Apr 18, 2018
    Posts:
    22
    The good old file-stuff is what i wanted all the time. I get rid of the
    Code (CSharp):
    1. //TextAsset textAsset = new TextAsset();
    2. //AssetDatabase.Refresh();
    3. //AssetDatabase.CreateAsset(textAsset, "Assets/Resources/data.txt");
    and still, everything works fine. The error is gone, too.

    Solution to my problem was:
    AssetDatabase.SaveAssets();
    AssetDatabase.Refresh();