Search code examples
ios8xamarinfilestream

Writing stream to file crashes on Xamarin iOS8


I am creating a HttpWebRequest to download a file.

HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);

Now on success, I get the response stream and try to write it file.

Stream responseStream = myHttpWebRequest.GetResponseStream();
DirectoryInfo di = new DirectoryInfo(url);
string documents = "";
if(UIDevice.CurrentDevice.CheckSystemVersion(8,0))
    documents = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0].ToString();
else
    documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // iOS 7 and earlier

var filename = Path.Combine(documents, di.Name);
FileStream fstr = new FileStream(filename, FileMode.OpenOrCreate,FileAccess.Write);
responseStream.CopyTo(fstr);

The code for iOS7 works perfects fine. But on iOS8 condition, the document and the filename that I get is "file:///Users/bharathkamath/Library/Developer/CoreSimulator/Devices/1FC25FA1-835A-414B-81FD-34B58F9EC16E/data/Containers/Data/Application/C70F4B4D-1DBB-427C-8CF7-2A09967A864C/Documents/4 QA doc 15.docx" and which is a valid file path. (I checked the folder structure.)

Now when I create a new file stream, I get an exception that some of the sub folders are missing because the path has now changed to

/Users/bharathkamath/Library/Developer/CoreSimulator/Devices/1FC25FA1-835A-414B-81FD-34B58F9EC16E/data/Containers/Bundle/Application/9D9D6488-25C1-4F1A-8F3D-

The /Containers/Data/ has changed to /Containers/Bundle/.

Any idea why the new FileStream changes the path?

Edit : Exception

Unhandled Exception:  ​System.IO.DirectoryNotFoundException: Could not find a part of the path "/Users/bharathkamath/Library/Developer/CoreSimulator/Devices/1FC25FA1-835A-414B-81FD-34B58F9EC16E/data/Containers/Bundle/Application/3B84B11D-CF99-41A5-BBA5-1B170B0A9574/RBCPPLMobileiOS.app/file:///Users/bharathkamath/Library/Developer/CoreSimulator/Devices/1FC25FA1-835A-414B-81FD-34B58F9EC16E/data/Containers/Data/Application/E214C51F-3260-455A-850E-7C3C5A5E9460/Documents/test.docx".

Solution

  • The directories are correct, as the iOS 8 simulator has changed the file structure, as you can see. But I think the problem with your code is this line:

    documents = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0].ToString();
    

    At the end of the line you're calling the "ToString()" method. "ToString()" will return the file path starting with "file://". Then later on you're trying to copy the file using C# (Mono) using a FileStream. Well, C# (Mono) does not like its paths starting with "file://". So you'll have to get rid of that.

    The easiest way to do this is to call the ".Path" property instead of the ".ToString()" method. This will return the path without the "file://" in it.

    documents = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0].Path;
    

    That should be in the format that C# likes and should work as expected. Don't forget to close you're file streams too so that the file gets written.