338 lines
12 KiB
C#
338 lines
12 KiB
C#
#if NETFX_CORE
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
using Windows.Storage;
|
|
using Windows.Storage.Streams;
|
|
using Windows.Foundation;
|
|
|
|
namespace BestHTTP.PlatformSupport.IO
|
|
{
|
|
public class FileStream : Stream
|
|
{
|
|
private int readTimeout = -1;
|
|
private int writeTimeout = 1000;
|
|
internal const int DefaultBufferSize = 8192;
|
|
private FileRandomAccessStream backend;
|
|
private FileOptions fileOptions;
|
|
private string name;
|
|
|
|
public override bool CanRead { get { return this.backend.CanRead; } }
|
|
public override bool CanSeek { get { return true; } }
|
|
public override bool CanWrite { get { return this.backend.CanWrite; } }
|
|
public virtual bool IsAsync { get { return (this.fileOptions & FileOptions.Asynchronous) > FileOptions.None; } }
|
|
public override long Length { get { return (long)this.backend.Size; } }
|
|
public override int ReadTimeout { get { return this.readTimeout; } set { this.readTimeout = value; } }
|
|
public override int WriteTimeout { get { return this.writeTimeout; } set { this.writeTimeout = value; } }
|
|
|
|
public string Name { get { return this.name; } }
|
|
|
|
public override long Position
|
|
{
|
|
get { return (long)this.backend.Position; }
|
|
set
|
|
{
|
|
try
|
|
{
|
|
this.backend.Seek((ulong)value);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw FileStream.RethrowException(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
public FileStream(string file, FileMode mode)
|
|
: this(file, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, FileShare.Read, 8192, FileOptions.None)
|
|
{
|
|
}
|
|
|
|
public FileStream(string file, FileMode mode, FileAccess access)
|
|
: this(file, mode, access, FileShare.Read, 8192, FileOptions.None)
|
|
{
|
|
}
|
|
|
|
public FileStream(string file, FileMode mode, FileAccess access, FileShare share)
|
|
: this(file, mode, access, share, 8192, FileOptions.None)
|
|
{
|
|
}
|
|
|
|
public FileStream(string file, FileMode mode, FileAccess access, FileShare share, int bufferSize)
|
|
: this(file, mode, access, share, bufferSize, FileOptions.None)
|
|
{
|
|
}
|
|
|
|
public FileStream(string file, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
|
|
: this(file, mode, access, share, bufferSize, useAsync ? FileOptions.Asynchronous : FileOptions.None)
|
|
{
|
|
}
|
|
|
|
public FileStream(string file, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
|
|
{
|
|
try
|
|
{
|
|
this.fileOptions = options;
|
|
this.name = file;
|
|
this.CheckAccess(mode, access);
|
|
StorageFile storageFile;
|
|
switch (mode)
|
|
{
|
|
case FileMode.CreateNew:
|
|
case FileMode.Create:
|
|
case FileMode.OpenOrCreate:
|
|
case FileMode.Append:
|
|
storageFile = FileStream.CreateFile(file, mode, access);
|
|
break;
|
|
case FileMode.Open:
|
|
case FileMode.Truncate:
|
|
storageFile = FileStream.OpenFile(file, mode, access);
|
|
break;
|
|
default:
|
|
throw new ArgumentException("Unknown file mode");
|
|
}
|
|
IAsyncOperation<IRandomAccessStream> source = storageFile.OpenAsync(FileStream.GetAccessMode(access));
|
|
WindowsRuntimeSystemExtensions.AsTask<IRandomAccessStream>(source).Wait();
|
|
this.backend = (FileRandomAccessStream)source.GetResults();
|
|
if (mode == FileMode.Truncate)
|
|
{
|
|
this.backend.Size = 0UL;
|
|
}
|
|
else
|
|
{
|
|
if (mode != FileMode.Append)
|
|
return;
|
|
this.backend.Seek(this.backend.Size);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw FileStream.RethrowException(ex);
|
|
}
|
|
}
|
|
|
|
private void CheckAccess(FileMode mode, FileAccess access)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case FileMode.CreateNew:
|
|
break;
|
|
case FileMode.Create:
|
|
break;
|
|
case FileMode.Open:
|
|
break;
|
|
case FileMode.OpenOrCreate:
|
|
break;
|
|
case FileMode.Truncate:
|
|
break;
|
|
case FileMode.Append:
|
|
if (access == FileAccess.Write)
|
|
break;
|
|
else
|
|
{
|
|
System.Diagnostics.Debug.WriteLine("FileStream.CheckAccess: Bad access mode for Append");
|
|
throw new IOException("Bad access mode for Append");
|
|
}
|
|
default:
|
|
throw new ArgumentException("Unknown file mode");
|
|
}
|
|
}
|
|
|
|
private static StorageFile OpenFile(string file, FileMode mode, FileAccess access)
|
|
{
|
|
return FileHelper.GetFileForPathOrURI(file);
|
|
}
|
|
|
|
private static StorageFile CreateFile(string file, FileMode mode, FileAccess access)
|
|
{
|
|
IAsyncOperation<StorageFile> fileAsync = FileHelper.GetFolderForPathOrURI(file).CreateFileAsync(Path.GetFileName(file), FileStream.GetCollisionOption(mode, access));
|
|
WindowsRuntimeSystemExtensions.AsTask<StorageFile>(fileAsync).Wait();
|
|
if (fileAsync.Status != AsyncStatus.Completed)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine("FileStream.CheckAccess: Failed to create file " + file);
|
|
throw new IOException("Failed to create file " + file);
|
|
}
|
|
else
|
|
return fileAsync.GetResults();
|
|
}
|
|
|
|
public override void Flush()
|
|
{
|
|
try
|
|
{
|
|
WindowsRuntimeSystemExtensions.AsTask<bool>(this.backend.FlushAsync()).Wait();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw FileStream.RethrowException(ex);
|
|
}
|
|
}
|
|
|
|
public void Flush(bool flushToDisc)
|
|
{
|
|
Flush();
|
|
}
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
try
|
|
{
|
|
Windows.Storage.Streams.Buffer buffer1 = new Windows.Storage.Streams.Buffer((uint)count);
|
|
WindowsRuntimeSystemExtensions.AsTask<IBuffer, uint>(this.backend.ReadAsync((IBuffer)buffer1, (uint)count, InputStreamOptions.ReadAhead)).Wait(this.readTimeout);
|
|
int length = (int)buffer1.Length;
|
|
DataReader dataReader = DataReader.FromBuffer((IBuffer)buffer1);
|
|
bool flag = offset == 0 && buffer.Length == count && length == count;
|
|
byte[] numArray = flag ? buffer : new byte[length];
|
|
dataReader.ReadBytes(numArray);
|
|
if (!flag)
|
|
Array.Copy((Array)numArray, 0, (Array)buffer, offset, numArray.Length);
|
|
return length;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw FileStream.RethrowException(ex);
|
|
}
|
|
}
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
try
|
|
{
|
|
switch (origin)
|
|
{
|
|
case SeekOrigin.Begin:
|
|
if (offset > (long)this.backend.Size)
|
|
{
|
|
offset = (long)this.backend.Size;
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
case SeekOrigin.Current:
|
|
if ((long)this.backend.Position + offset > (long)this.backend.Size)
|
|
{
|
|
offset = (long)this.backend.Position + offset;
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
case SeekOrigin.End:
|
|
if (offset >= 0L)
|
|
{
|
|
offset = (long)this.backend.Size;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
offset += (long)this.backend.Size;
|
|
break;
|
|
}
|
|
}
|
|
if (offset < 0L)
|
|
offset = 0L;
|
|
this.backend.Seek((ulong)offset);
|
|
return offset;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw FileStream.RethrowException(ex);
|
|
}
|
|
}
|
|
|
|
public override void SetLength(long value)
|
|
{
|
|
try
|
|
{
|
|
this.backend.Size = (ulong)value;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw FileStream.RethrowException(ex);
|
|
}
|
|
}
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
try
|
|
{
|
|
Windows.Storage.Streams.Buffer buffer1 = new Windows.Storage.Streams.Buffer((uint)count);
|
|
byte[] numArray;
|
|
if (offset == 0 && count == buffer.Length)
|
|
{
|
|
numArray = buffer;
|
|
}
|
|
else
|
|
{
|
|
numArray = new byte[count];
|
|
Array.Copy((Array)buffer, offset, (Array)numArray, 0, count);
|
|
}
|
|
DataWriter dataWriter = new DataWriter();
|
|
dataWriter.WriteBytes(numArray);
|
|
WindowsRuntimeSystemExtensions.AsTask<uint, uint>(this.backend.WriteAsync(dataWriter.DetachBuffer())).Wait(this.writeTimeout);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw FileStream.RethrowException(ex);
|
|
}
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
base.Dispose(disposing);
|
|
this.backend.Dispose();
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
base.Dispose();
|
|
}
|
|
|
|
private static Exception RethrowException(Exception e)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine("FileStream.RethrowException: " + e.Message + "\n" + e.StackTrace);
|
|
if (e.GetType() == typeof(IOException))
|
|
return e;
|
|
else
|
|
return (Exception)new IOException(e.Message, e);
|
|
}
|
|
|
|
private static CreationCollisionOption GetCollisionOption(FileMode mode, FileAccess access)
|
|
{
|
|
CreationCollisionOption creationCollisionOption = CreationCollisionOption.GenerateUniqueName;
|
|
switch (mode)
|
|
{
|
|
case FileMode.CreateNew:
|
|
creationCollisionOption = CreationCollisionOption.FailIfExists;
|
|
break;
|
|
case FileMode.Create:
|
|
case FileMode.Truncate:
|
|
creationCollisionOption = CreationCollisionOption.ReplaceExisting;
|
|
break;
|
|
case FileMode.Open:
|
|
case FileMode.OpenOrCreate:
|
|
case FileMode.Append:
|
|
creationCollisionOption = CreationCollisionOption.OpenIfExists;
|
|
break;
|
|
}
|
|
return creationCollisionOption;
|
|
}
|
|
|
|
private static FileAccessMode GetAccessMode(FileAccess access)
|
|
{
|
|
switch (access)
|
|
{
|
|
case FileAccess.Read:
|
|
return FileAccessMode.Read;
|
|
default:
|
|
return FileAccessMode.ReadWrite;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif |