Reputation: 1070
Its stated that by using Stream.SetLength
the stream is truncated.
source
I need to set the length of the stream without truncation.
Any build-in possibilities?
UPDATE: I need to read a subset of a file. the file format: size + data(string format).
Im using StreamReader
UPDATE2:
Im also veryintrested in using ReadLine
from the StreamReader
class.
Upvotes: 0
Views: 2750
Reputation: 134611
You're asking the wrong question here. The Length
of a stream is the known amount of bytes are available to be read from the stream. Setting the length of the stream alters the source to ensure it uses the length specified.
Since you merely want to limit how much you read from the stream, just read as much as you need and close it. You don't need to do anything else.
Since it appears you're trying to read a text file, just go with the normal file reading patterns and come up with an appropriate stop condition. You won't even need a stream, the File
class provides simple ways to read the lines of a file.
foreach (var line in File.ReadLines(path))
{
// do something with line...
if (line == "end of interesting section")
break;
}
Upvotes: 0
Reputation: 17474
I agree with @usr's answer about creating a subclass Stream wrapper. Here's a sample implementation which forwards all calls to the "inner" stream, but gets involved during reading or when asked for Length. Anything involving writing is unsupported with this implementation.
I haven't fully tested this implementation and I welcome edits from the community:
sealed class StreamReadLimitLengthWrapper : Stream
{
readonly Stream m_innerStream;
readonly long m_endPosition;
public StreamReadLimitLengthWrapper(Stream innerStream, int size)
{
if (innerStream == null) throw new ArgumentNullException("innerStream");
if (size < 0) throw new ArgumentOutOfRangeException("size");
m_innerStream = innerStream;
m_endPosition = m_innerStream.Position + size;
}
public override bool CanRead
{
get { return m_innerStream.CanRead; }
}
public override bool CanSeek
{
get { return m_innerStream.CanSeek; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
m_innerStream.Flush();
}
public override long Length
{
get { return m_endPosition; }
}
public override long Position
{
get
{
return m_innerStream.Position;
}
set
{
m_innerStream.Position = value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
count = GetAllowedCount(count);
return m_innerStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return m_innerStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override bool CanTimeout { get { return m_innerStream.CanTimeout; } }
public override int ReadTimeout
{
get
{
return m_innerStream.ReadTimeout;
}
set
{
m_innerStream.ReadTimeout = value;
}
}
public override int WriteTimeout
{
get
{
return m_innerStream.ReadTimeout;
}
set
{
m_innerStream.ReadTimeout = value;
}
}
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
count = GetAllowedCount(count);
return m_innerStream.BeginRead(buffer, offset, count, callback, state);
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
throw new NotSupportedException();
}
public override void Close()
{
// Since this wrapper does not own the underlying stream, we do not want it to close the underlying stream
}
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
return m_innerStream.CopyToAsync(destination, bufferSize, cancellationToken);
}
public override int EndRead(IAsyncResult asyncResult)
{
return m_innerStream.EndRead(asyncResult);
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
return m_innerStream.FlushAsync(cancellationToken);
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
count = GetAllowedCount(count);
return m_innerStream.ReadAsync(buffer, offset, count, cancellationToken);
}
public override int ReadByte()
{
int count = GetAllowedCount(1);
if (count == 0)
return -1;
return m_innerStream.ReadByte();
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
throw new NotSupportedException();
}
public override void WriteByte(byte value)
{
throw new NotSupportedException();
}
private int GetAllowedCount(int count)
{
long pos = m_innerStream.Position;
long maxCount = m_endPosition - pos;
if (count > maxCount)
count = (int)maxCount;
return count;
}
}
Upvotes: 1
Reputation: 171246
I need to read a subset of a file
OK, so you do not want to set the length actually. You want to read a particular length.
Write yourself a Stream
subclass that reads only a certain amount of bytes. Then, you can wrap the file stream with that class and StreamReader
will just work.
Or, if buffering the data is OK, you do this:
var limitedStream = new MemoryStream(new BinaryReader(myStream).ReadBytes(length));
Upvotes: 2