Unity IOException: Sharing violation on path for output_log.txt, how to read a file in use?

Viewed 2824

I am getting the following exception in my game build when trying to upload the file to a remote url.

IOException: Sharing violation on path C:\Users\vipin\AppData\LocalLow\DefaultCompany\ChemOcrypt\output_log.txt
  at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) [0x0019e] in <f826c2584fc94ec19a48a6576640bdc5>:0 
  at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) [0x00000] in <f826c2584fc94ec19a48a6576640bdc5>:0 
  at (wrapper remoting-invoke-with-check) System.IO.FileStream..ctor(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
  at System.IO.File.OpenRead (System.String path) [0x00000] in <f826c2584fc94ec19a48a6576640bdc5>:0 
  at System.IO.File.ReadAllBytes (System.String path) [0x00000] in <f826c2584fc94ec19a48a6576640bdc5>:0 
  at PopulateTest.submitToGoogleSheet () [0x00b99] in <a5e233b1914d4eecaae056ee383cbe4d>:0 
  at PopulateTest.EvaluateScore () [0x00221] in <a5e233b1914d4eecaae056ee383cbe4d>:0 
  at UnityEngine.Events.InvokableCall.Invoke () [0x00011] in <b44fd21d6d27420ebf318fe55aef0978>:0 
  at UnityEngine.Events.UnityEvent.Invoke () [0x00023] in <b44fd21d6d27420ebf318fe55aef0978>:0 
  at UnityEngine.UI.Button.Press () [0x00027] in <b864ecc7b7bb4f98a1934b2a75272d9c>:0 
  at UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) [0x00011] in <b864ecc7b7bb4f98a1934b2a75272d9c>:0 
  at UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) [0x00008] in <b864ecc7b7bb4f98a1934b2a75272d9c>:0 
  at UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) [0x00070] in <b864ecc7b7bb4f98a1934b2a75272d9c>:0

The exception occurs because the game is writing the data continuously to output file. How do I read the contents of file in when it is already being used for uploading to a server?

Below is my piece of code which is responsible for uploading this output_log.txt file.

string FILEUPLOAD_BASE_URL = GameSession.FILEUPLOAD_BASE_URL;
string[] files = Directory.GetFiles(Application.persistentDataPath, "output*");
if (files.Length > 0)
{
    UnityEngine.WWWForm outputForm = new WWWForm();
    outputForm.AddField("key", "OutputLogsEXP2/${filename}");
    string fileName = Path.GetFileName(files[0]);
    outputForm.AddBinaryData("file", File.ReadAllBytes(files[0]), fileName, "text/plain");
    StartCoroutine(PostDataToForm(FILEUPLOAD_BASE_URL, outputForm));
}

IEnumerator PostDataToForm(string url, WWWForm form)
{
    WWW www = new WWW(url, form);
    float elapsedTime = 0.0f;
    while (!www.isDone)
    {
        elapsedTime += Time.deltaTime;
        //Matrix4x4 wait time is 120s
        if (elapsedTime >= 120f)
        {
            break;
        }
        yield return null;
    }
    if (!www.isDone || !string.IsNullOrEmpty(www.error))
    {
        Debug.LogError("Connection error while sending analytics from PopulateTest... Error:" + www.error);
        // Error handling here.
        yield break;
    }

    if (www.isDone)
    {
        Debug.Log("Data Sent successfully.");
        yield break;
    }
}
1 Answers

During my local tests, I was able to access and read output_log with the following code. By the way please keep in mind that when you use File.ReadAllBytes, it will try to access the file with the following parameters:

using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,.....)

FileMode.Open   → Operating system should open an existing file.
FileAccess.Read → Data can be read from the file
FileShare.Read  → Allows subsequent opening of the file for reading or writing.

So basically FileAccess specifies what USER wants to do with the file. FileShare specifies what OTHERS can do with the file while the said file is being used.

Example code to read output log:

private byte[] GetBytesFromFilePath(string pathToOutputLog) {
    using (var fileStream = File.Open(pathToOutputLog, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
    using (var memoryStream = new MemoryStream()) {
        fileStream.CopyTo(memoryStream);
        return memoryStream.ToArray();
    }
} 
Related