Reputation: 129
I have 30 GB FileStream. I want to get 2 (or more) Streams from it, beginning (0-50%) and the end (50%-100%). If I use MemoryStream and CopyTo(), it will consume 30 GB of RAM, while I just need new separated streams. Is this possible?
Upvotes: 1
Views: 1084
Reputation: 13
I've further improved upon the file and implemented the Seek function upon the work @Shamork.Fu did
using System;
using System.IO;
namespace DataStoreFramework
{
public class PartialReadStream : Stream
{
private readonly Stream _stream;
private readonly long _streamStart;
private readonly long _streamLength;
private readonly long _streamEnd;
private readonly long _streamEndOffset;
private readonly long _streamMaxEndOffset;
public PartialReadStream(Stream stream,long offset, long size)
{
_stream = stream;
_streamStart = offset;
_streamLength = size;
_streamEnd = offset + size;
_streamEndOffset = _streamEnd - _stream.Length;
_streamMaxEndOffset = _streamLength + _stream.Length - _streamEnd;
if (_stream.CanSeek) {
_stream.Seek(offset, SeekOrigin.Begin);
}
else {
_stream.Position = offset;
}
}
public override bool CanRead => _stream.CanRead;
public override bool CanSeek => _stream.CanSeek;
public override bool CanWrite => false;
public override long Length => Math.Min((_stream.Length - _streamStart), _streamLength);
public override long Position
{
get => _stream.Position - _streamStart;
set => _stream.Position = _streamStart + value;
}
public override void Flush() {
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, [NonNegativeValue]int count)
{
var p = _stream.Position;
if (p < _streamStart) {
_stream.Position = _streamStart;
}
if (p > _streamEnd) {
return 0;
}
if (p + count > _streamEnd) {
count = (int)(_streamEnd - p);
}
return _stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
long seekValue = 0;
switch (origin)
{
case SeekOrigin.Begin:
if (offset < 0) {
throw new IOException("IO.IO_SeekBeforeBegin");
}
seekValue = _streamStart + offset;
break;
case SeekOrigin.End:
seekValue = _streamEndOffset + offset;
if (seekValue < -_streamMaxEndOffset) {
throw new IOException("IO.IO_SeekBeforeBegin");
}
break;
case SeekOrigin.Current:
seekValue = offset;
if (_stream.Position + seekValue < 0) {
throw new IOException("IO.IO_SeekBeforeBegin");
}
break;
}
return _stream.Seek(seekValue, origin) - _streamStart;
}
public override void SetLength(long value) =>
throw new NotImplementedException();
public override void Write(byte[] buffer, int offset, int count) =>
throw new NotImplementedException();
}
}
Upvotes: 0
Reputation: 53
impovements for SegmentedStream by @Andrew
public class PartialStream : Stream
{
public Stream Stream { get; private set; }
public long StreamStart { get; private set; }
public long StreamLength { get; private set; }
public long StreamEnd{get; private set;}
public PartialStream(Stream stream, long offset, long size)
{
Stream = stream;
StreamStart = offset;
StreamLength = size;
StreamEnd=offset+size;
stream.Seek(offset, SeekOrigin.Begin);
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => Math.Min((Stream.Length - StreamStart), StreamLength);
public override long Position
{
get => Stream.Position - StreamStart;
set => Stream.Position = StreamStart + value;
}
public override void Flush()
{
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
var p=Stream.Position;
if (p < StreamStart)
{
Stream.Position = StreamStart;
}
if (p > StreamEnd)//EOF
{
return 0;
}
if (p + count > StreamEnd)
{
count = (int)(StreamEnd-p);
}
return Stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
//Seek will be complicated as there are three origin types.
//you can do it yourself
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
Upvotes: 4
Reputation: 129
I made own Stream for this task. Not tested well but looks okay
class SegmentedStream : Stream
{
Stream Stream { get; set; }
long StreamStart { get; set; }
long StreamLength { get; set; }
public SegmentedStream(Stream stream, long position, long size)
{
Stream = stream;
StreamStart = position;
StreamLength = size;
}
public override bool CanRead => true;
public override bool CanSeek => true;
public override bool CanWrite => false;
public override long Length => Math.Min((Stream.Length - StreamStart), StreamLength);
public override long Position { get => Stream.Position - StreamStart; set => Stream.Position = StreamStart + value; }
public override void Flush()
{
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
return Stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return Stream.Seek(StreamStart + offset, origin);
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
Upvotes: 2