Skip to content

Instantly share code, notes, and snippets.

@marcussacana
Created September 15, 2021 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcussacana/6b400d72751a237e1d3c781713ce9b94 to your computer and use it in GitHub Desktop.
Save marcussacana/6b400d72751a237e1d3c781713ce9b94 to your computer and use it in GitHub Desktop.
Random Access Stream (WIP)
public class ReadSeekableStream : Stream, IDisposable
{
private readonly Stream Buffer;
private readonly Stream InputStream;
string TempFile = Path.GetTempFileName();
public ReadSeekableStream(Stream Input)
{
if (!Input.CanRead)
throw new Exception("Provided stream " + Input + " is not readable");
InputStream = Input;
Buffer = new FileStream(TempFile, FileMode.OpenOrCreate, FileSystemRights.FullControl, FileShare.Read, 4096, FileOptions.RandomAccess, new FileSecurity());
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return true; } }
public override int Read(byte[] buffer, int offset, int count)
{
if (ReadPosition < InputPosition) {
Buffer.Position = ReadPosition;
int bReaded = Buffer.Read(buffer, offset, count);
ReadPosition += bReaded;
return bReaded;
}
if (ReadPosition > InputPosition) {
long Skiped = ReadPosition - InputPosition;
Buffer.Seek(0, SeekOrigin.End);
Skiped = Copy(InputStream, Buffer, Skiped);
InputPosition += Skiped;
}
if (ReadPosition != InputPosition)
throw new Exception("Bad Buffer Offset");
int Readed = InputStream.Read(buffer, offset, count);
Buffer.Write(buffer, offset, Readed);
ReadPosition += Readed;
InputPosition += Readed;
return Readed;
}
public override long Seek(long offset, SeekOrigin origin)
{
long AbsoluteOffset = origin switch
{
SeekOrigin.Begin => offset,
SeekOrigin.Current => ReadPosition + offset,
SeekOrigin.End => InputStream.Length + offset,
_ => throw new Exception("Invalid Seek Origin")
};
return ReadPosition = AbsoluteOffset;
}
long Copy(Stream From, Stream To, long Length) {
byte[] Buffer = new byte[1024 * 100];
long TotalReaded = 0;
int Readed;
do
{
long Reaming = Length - TotalReaded;
Readed = From.Read(Buffer, 0, Reaming > Buffer.Length ? Buffer.Length : (int)Reaming);
To.Write(Buffer, 0, Readed);
TotalReaded += Readed;
} while (Readed > 0);
To.Flush();
return TotalReaded;
}
long ReadPosition = 0;
long InputPosition = 0;
public override long Position
{
get { return ReadPosition; }
set { ReadPosition = value; }
}
public override void Close()
{
Buffer?.Close();
Buffer?.Dispose();
if (File.Exists(TempFile))
File.Delete(TempFile);
base.Close();
}
protected override void Dispose(bool disposing)
{
if (disposing)
InputStream.Close();
Buffer?.Close();
Buffer?.Dispose();
if (File.Exists(TempFile))
File.Delete(TempFile);
base.Dispose(disposing);
}
public override bool CanTimeout { get { return InputStream.CanTimeout; } }
public override bool CanWrite { get { return InputStream.CanWrite; } }
public override long Length { get { return InputStream.Length; } }
public override void SetLength(long value) { InputStream.SetLength(value); }
public override void Write(byte[] buffer, int offset, int count) { InputStream.Write(buffer, offset, count); }
public override void Flush() { InputStream.Flush(); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment