FileStream.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. #if NETFX_CORE
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Threading.Tasks;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using Windows.Storage;
  9. using Windows.Storage.Streams;
  10. using Windows.Foundation;
  11. namespace BestHTTP.PlatformSupport.IO
  12. {
  13. public class FileStream : Stream
  14. {
  15. private int readTimeout = -1;
  16. private int writeTimeout = 1000;
  17. internal const int DefaultBufferSize = 8192;
  18. private FileRandomAccessStream backend;
  19. private FileOptions fileOptions;
  20. private string name;
  21. public override bool CanRead { get { return this.backend.CanRead; } }
  22. public override bool CanSeek { get { return true; } }
  23. public override bool CanWrite { get { return this.backend.CanWrite; } }
  24. public virtual bool IsAsync { get { return (this.fileOptions & FileOptions.Asynchronous) > FileOptions.None; } }
  25. public override long Length { get { return (long)this.backend.Size; } }
  26. public override int ReadTimeout { get { return this.readTimeout; } set { this.readTimeout = value; } }
  27. public override int WriteTimeout { get { return this.writeTimeout; } set { this.writeTimeout = value; } }
  28. public string Name { get { return this.name; } }
  29. public override long Position
  30. {
  31. get { return (long)this.backend.Position; }
  32. set
  33. {
  34. try
  35. {
  36. this.backend.Seek((ulong)value);
  37. }
  38. catch (Exception ex)
  39. {
  40. throw FileStream.RethrowException(ex);
  41. }
  42. }
  43. }
  44. public FileStream(string file, FileMode mode)
  45. : this(file, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, FileShare.Read, 8192, FileOptions.None)
  46. {
  47. }
  48. public FileStream(string file, FileMode mode, FileAccess access)
  49. : this(file, mode, access, FileShare.Read, 8192, FileOptions.None)
  50. {
  51. }
  52. public FileStream(string file, FileMode mode, FileAccess access, FileShare share)
  53. : this(file, mode, access, share, 8192, FileOptions.None)
  54. {
  55. }
  56. public FileStream(string file, FileMode mode, FileAccess access, FileShare share, int bufferSize)
  57. : this(file, mode, access, share, bufferSize, FileOptions.None)
  58. {
  59. }
  60. public FileStream(string file, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
  61. : this(file, mode, access, share, bufferSize, useAsync ? FileOptions.Asynchronous : FileOptions.None)
  62. {
  63. }
  64. public FileStream(string file, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
  65. {
  66. try
  67. {
  68. this.fileOptions = options;
  69. this.name = file;
  70. this.CheckAccess(mode, access);
  71. StorageFile storageFile;
  72. switch (mode)
  73. {
  74. case FileMode.CreateNew:
  75. case FileMode.Create:
  76. case FileMode.OpenOrCreate:
  77. case FileMode.Append:
  78. storageFile = FileStream.CreateFile(file, mode, access);
  79. break;
  80. case FileMode.Open:
  81. case FileMode.Truncate:
  82. storageFile = FileStream.OpenFile(file, mode, access);
  83. break;
  84. default:
  85. throw new ArgumentException("Unknown file mode");
  86. }
  87. IAsyncOperation<IRandomAccessStream> source = storageFile.OpenAsync(FileStream.GetAccessMode(access));
  88. WindowsRuntimeSystemExtensions.AsTask<IRandomAccessStream>(source).Wait();
  89. this.backend = (FileRandomAccessStream)source.GetResults();
  90. if (mode == FileMode.Truncate)
  91. {
  92. this.backend.Size = 0UL;
  93. }
  94. else
  95. {
  96. if (mode != FileMode.Append)
  97. return;
  98. this.backend.Seek(this.backend.Size);
  99. }
  100. }
  101. catch (Exception ex)
  102. {
  103. throw FileStream.RethrowException(ex);
  104. }
  105. }
  106. private void CheckAccess(FileMode mode, FileAccess access)
  107. {
  108. switch (mode)
  109. {
  110. case FileMode.CreateNew:
  111. break;
  112. case FileMode.Create:
  113. break;
  114. case FileMode.Open:
  115. break;
  116. case FileMode.OpenOrCreate:
  117. break;
  118. case FileMode.Truncate:
  119. break;
  120. case FileMode.Append:
  121. if (access == FileAccess.Write)
  122. break;
  123. else
  124. {
  125. System.Diagnostics.Debug.WriteLine("FileStream.CheckAccess: Bad access mode for Append");
  126. throw new IOException("Bad access mode for Append");
  127. }
  128. default:
  129. throw new ArgumentException("Unknown file mode");
  130. }
  131. }
  132. private static StorageFile OpenFile(string file, FileMode mode, FileAccess access)
  133. {
  134. return FileHelper.GetFileForPathOrURI(file);
  135. }
  136. private static StorageFile CreateFile(string file, FileMode mode, FileAccess access)
  137. {
  138. IAsyncOperation<StorageFile> fileAsync = FileHelper.GetFolderForPathOrURI(file).CreateFileAsync(Path.GetFileName(file), FileStream.GetCollisionOption(mode, access));
  139. WindowsRuntimeSystemExtensions.AsTask<StorageFile>(fileAsync).Wait();
  140. if (fileAsync.Status != AsyncStatus.Completed)
  141. {
  142. System.Diagnostics.Debug.WriteLine("FileStream.CheckAccess: Failed to create file " + file);
  143. throw new IOException("Failed to create file " + file);
  144. }
  145. else
  146. return fileAsync.GetResults();
  147. }
  148. public override void Flush()
  149. {
  150. try
  151. {
  152. WindowsRuntimeSystemExtensions.AsTask<bool>(this.backend.FlushAsync()).Wait();
  153. }
  154. catch (Exception ex)
  155. {
  156. throw FileStream.RethrowException(ex);
  157. }
  158. }
  159. public void Flush(bool flushToDisc)
  160. {
  161. Flush();
  162. }
  163. public override int Read(byte[] buffer, int offset, int count)
  164. {
  165. try
  166. {
  167. Windows.Storage.Streams.Buffer buffer1 = new Windows.Storage.Streams.Buffer((uint)count);
  168. WindowsRuntimeSystemExtensions.AsTask<IBuffer, uint>(this.backend.ReadAsync((IBuffer)buffer1, (uint)count, InputStreamOptions.ReadAhead)).Wait(this.readTimeout);
  169. int length = (int)buffer1.Length;
  170. DataReader dataReader = DataReader.FromBuffer((IBuffer)buffer1);
  171. bool flag = offset == 0 && buffer.Length == count && length == count;
  172. byte[] numArray = flag ? buffer : new byte[length];
  173. dataReader.ReadBytes(numArray);
  174. if (!flag)
  175. Array.Copy((Array)numArray, 0, (Array)buffer, offset, numArray.Length);
  176. return length;
  177. }
  178. catch (Exception ex)
  179. {
  180. throw FileStream.RethrowException(ex);
  181. }
  182. }
  183. public override long Seek(long offset, SeekOrigin origin)
  184. {
  185. try
  186. {
  187. switch (origin)
  188. {
  189. case SeekOrigin.Begin:
  190. if (offset > (long)this.backend.Size)
  191. {
  192. offset = (long)this.backend.Size;
  193. break;
  194. }
  195. else
  196. break;
  197. case SeekOrigin.Current:
  198. if ((long)this.backend.Position + offset > (long)this.backend.Size)
  199. {
  200. offset = (long)this.backend.Position + offset;
  201. break;
  202. }
  203. else
  204. break;
  205. case SeekOrigin.End:
  206. if (offset >= 0L)
  207. {
  208. offset = (long)this.backend.Size;
  209. break;
  210. }
  211. else
  212. {
  213. offset += (long)this.backend.Size;
  214. break;
  215. }
  216. }
  217. if (offset < 0L)
  218. offset = 0L;
  219. this.backend.Seek((ulong)offset);
  220. return offset;
  221. }
  222. catch (Exception ex)
  223. {
  224. throw FileStream.RethrowException(ex);
  225. }
  226. }
  227. public override void SetLength(long value)
  228. {
  229. try
  230. {
  231. this.backend.Size = (ulong)value;
  232. }
  233. catch (Exception ex)
  234. {
  235. throw FileStream.RethrowException(ex);
  236. }
  237. }
  238. public override void Write(byte[] buffer, int offset, int count)
  239. {
  240. try
  241. {
  242. Windows.Storage.Streams.Buffer buffer1 = new Windows.Storage.Streams.Buffer((uint)count);
  243. byte[] numArray;
  244. if (offset == 0 && count == buffer.Length)
  245. {
  246. numArray = buffer;
  247. }
  248. else
  249. {
  250. numArray = new byte[count];
  251. Array.Copy((Array)buffer, offset, (Array)numArray, 0, count);
  252. }
  253. DataWriter dataWriter = new DataWriter();
  254. dataWriter.WriteBytes(numArray);
  255. WindowsRuntimeSystemExtensions.AsTask<uint, uint>(this.backend.WriteAsync(dataWriter.DetachBuffer())).Wait(this.writeTimeout);
  256. }
  257. catch (Exception ex)
  258. {
  259. throw FileStream.RethrowException(ex);
  260. }
  261. }
  262. protected override void Dispose(bool disposing)
  263. {
  264. base.Dispose(disposing);
  265. this.backend.Dispose();
  266. }
  267. public void Close()
  268. {
  269. base.Dispose();
  270. }
  271. private static Exception RethrowException(Exception e)
  272. {
  273. System.Diagnostics.Debug.WriteLine("FileStream.RethrowException: " + e.Message + "\n" + e.StackTrace);
  274. if (e.GetType() == typeof(IOException))
  275. return e;
  276. else
  277. return (Exception)new IOException(e.Message, e);
  278. }
  279. private static CreationCollisionOption GetCollisionOption(FileMode mode, FileAccess access)
  280. {
  281. CreationCollisionOption creationCollisionOption = CreationCollisionOption.GenerateUniqueName;
  282. switch (mode)
  283. {
  284. case FileMode.CreateNew:
  285. creationCollisionOption = CreationCollisionOption.FailIfExists;
  286. break;
  287. case FileMode.Create:
  288. case FileMode.Truncate:
  289. creationCollisionOption = CreationCollisionOption.ReplaceExisting;
  290. break;
  291. case FileMode.Open:
  292. case FileMode.OpenOrCreate:
  293. case FileMode.Append:
  294. creationCollisionOption = CreationCollisionOption.OpenIfExists;
  295. break;
  296. }
  297. return creationCollisionOption;
  298. }
  299. private static FileAccessMode GetAccessMode(FileAccess access)
  300. {
  301. switch (access)
  302. {
  303. case FileAccess.Read:
  304. return FileAccessMode.Read;
  305. default:
  306. return FileAccessMode.ReadWrite;
  307. }
  308. }
  309. }
  310. }
  311. #endif