Stream.Seek(0, Seekorigin.Begin) or Position = 0

Stream.Seek(0, SeekOrigin.Begin) or Position = 0

Use Position when setting an absolute position and Seek when setting a relative position. Both are provided for convenience so you can choose one that fits the style and readability of your code. Accessing Position requires the stream be seekable so they're safely interchangeable.

Streams Why Use Seek(0L, SeekOrigin.Begin) instead of Position = 0 or vice versa

As far as I can tell, at least for this specific case, nothing.

Both method Seek() and property Position require CanSeek to be true so from what I see it's up to the implementer.

Seek is really there to allow searching from specified locations (SeekOrigins) to an offset (the examples given on MSDN are somewhat convoluted but representative of the purpose: http://msdn.microsoft.com/en-us/library/system.io.filestream.seek.aspx).

Position is absolute and is obviously not meant for searching.

The case you mentioned just happens to be equivalent.

Personally, I'd use .Position = 0 to move to the beginning of the stream as that reads cleaner to me than "Seek using the beginning of the file as an origin and move this 0 offset of bytes."

Why returning MemoryStream sets the position on end

If SpreadsheetDocument writes to the Stream on Dispose it would cause that result. Try explicitly calling Flush/Close/Dispose before repositioning the Stream, eg:

document.Dispose();
memoryStream.Position = 0;
return memoryStream;

Why do I need to flush and set the stream position to 0 in this serialization snippet?

These samples contain unecessary code. The documentation for MemoryStream.ToArray (here) explicitly states that:

Writes the stream contents to a byte array, regardless of the Position
property.

Thus, we clearly don't need to set position. The flush is more debatable. It's very, very unlikely that memory stream would buffer under the hood, since it's just writing to a memory buffer anyway. However, I'm not sure that it's documented anywhere that memory stream won't buffer, so Flush() might be reasonable since we're calling ToArray() before disposing the stream. Another approach would be to call ToArray() outside the using block (we'd have to move the declaration of the variable out as well). This will work because ToArray() states that:

This method works when the MemoryStream is closed.

On the read side, you are creating a new stream, which starts at position 0 by default. Thus, there's no need for the Seek call.

Specified method is not supported while using SeekOrigin.Begin on stream

Not all streams support seeking. Stream has the CanSeek property, which is probably false in this case.

In this specific case, since you're reading the whole message into a string anyway, you can create a StringReader from the string and pass that into JsonTextReader instead of the StreamReader.

In other cases, you may need to find a different solution. For example, if you're reading an ASP.NET Core request stream, you can enable buffering to allow the stream to be read multiple times.

Advantage / Disadvantage MemoryStream.Position or MemoryStream.Seek

The only advantage of Position is a shorter, more direct notation.

The advantage of Seek(0, SeekOrigin.Begin) is that you also have SeekOrigin.Current and SeekOrigin.End.

But they are functionally the same, pick whatever you think is most readable.

C# .NET Why Stream.Seek is required when unzipping stream

When you return output from ZipObject, that stream is at the end - you've just written the data. You need to "rewind" it so that the data can then be read. Imagine you had a video cassette, and had just recorded a program - you'd need to rewind it before you watched it, right? It's exactly the same here.

I would suggest doing this in ZipObject itself though - and I don't believe the Flush call is necessary. I'd personally use the Position property, too:

public Stream ZipObject(Stream data)
{
var output = new MemoryStream();
using (var zip = new ZipFile())
{
zip.AddEntry(Name, data);
zip.Save(output);
}
output.Position = 0;
return output;
}

How to read a Stream and reset its position to zero even if stream.CanSeek == false

If your scenario permits you to replace your original stream, then you could check whether it supports seeking and, if not, read its content and wrap them into a new MemoryStream, which you could then use for subsequent operations.

static string PeekStream(ref Stream stream)
{
string content;
var reader = new StreamReader(stream);
content = reader.ReadToEnd();

if (stream.CanSeek)
{
stream.Seek(0, SeekOrigin.Begin);
}
else
{
stream.Dispose();
stream = new MemoryStream(Encoding.UTF8.GetBytes(content));
}

return content;
}

The above is rather inefficient, since it must allocate memory for twice the size of your content. My recommendation would be to adapt the parts of your code where you’re accessing the stream (after having read all its content) in order to make them access the stored copy of your content instead. For example:

string content;
using (var reader = new StreamReader(stream))
content = reader.ReadToEnd();

// Process content here.

string line;
using (var reader = new StringReader(content))
while ((line = reader.ReadLine()) != null)
Console.WriteLine(line);

Since the StringReader just reads from your content string, you would not waste memory creating redundant copies of your data.

Does FileStream.Seek() with SeekOrigin.Begin optimize for when no seeking is necessary?

The answer seems to be Yes.

The only concern here is the read buffer. We may assume the underlying SetFilePointer() call will be a non-op for a seek-to-current.

When you consult the source for Seek, you can see that an attempt is made to preserve as much as possible from the read buffer.

Attempted to seek before beginning of stream inside a using() statement

Are the commentors have posted: the file is less than 20000 bytes. It seems like you assume that Seek will stay at position 0 if the file is not large enough. It doesn't. It throws ArgumentException in that case.

Another thing. Seek will move the position for you. No need to do both. Either use:

fs.Seek(-20000, SeekOrigin.End);

or set the position:

fs.Position = fs.Length - 20000;

So what you really wanted to write is:

if (fs.Length > 20000)
fs.Seek(-20000, SeekOrigin.End);


Related Topics



Leave a reply



Submit