6

I am trying to figure out what I am doing wrong here. I am attempting to use a Binary Reader to ease getting an initial four bytes from a stream into an Int32 value that tells me how long the rest of the data is to be expected.

static void Main(string[] args)
{
    MemoryStream stream = new MemoryStream();

    BinaryWriter writer = new BinaryWriter(stream);

    string s = "Imagine this is a very very long string.";

    writer.Write(s.Length);
    writer.Write(s);
    writer.Flush();

    BinaryReader reader = new BinaryReader(stream);
    reader.BaseStream.Seek(0, SeekOrigin.Begin);

    char[] aChars = new char[reader.ReadInt32()];
    reader.Read(aChars, 0, aChars.Length);
    Console.WriteLine(new string(aChars));
}

The output should be the input, but I get this (Note that the first character changes from string to string)

(Imagine this is a very very long string

Can someone explain to me what I am doing wrong? Ideally the second read would continue until the total read bytes was equal to the value of the first four bytes.. this code is just a simplification to show the problem I am running into. The position of the stream seems correct (4) but it almost seems like it starts reading at 2.

James
  • 1,651
  • 2
  • 18
  • 24
  • Hehe, thanks... and I was. Unfortunately for me the BinaryReader doesnt mention that the Writer stores extra data for a string than the string ;) – James Nov 24 '10 at 00:28
  • `BinaryWriter.Write(string)`: "A length-prefixed `string` represents the `string` length by prefixing to the `string` a single byte or word that contains the length of that `string`. This method first writes the length of the `string` as a UTF-7 encoded unsigned integer, and then writes that many characters to the stream by using the `BinaryWriter` instance's current encoding." – jason Nov 24 '10 at 14:27
  • `BinaryReader.ReadString`: "Reads a `string` from the current stream. The `string` is prefixed with the length, encoded as an integer seven bits at a time." – jason Nov 24 '10 at 14:27

1 Answers1

8

BinaryWriter.Write(String) writes a length-prefixed string to this stream. This means it first writes the length of the string to the stream, and then the string using some encoding. The length is encoded seven bits at a time, not as 32-bit integer.

If you want to read from the stream, you should use BinaryReader.ReadString, which reads a length-prefixed string from the stream.

dtb
  • 213,145
  • 36
  • 401
  • 431
  • Will it automatically wait for the rest of the data to show up then if it does not initially have it in the stream? – James Nov 24 '10 at 00:12
  • Not only does it write the length first, but the length is written in a 7-bit encoding. So strings that are less than 128 bytes long have a one-byte length prefix, etc. – Jim Mischel Nov 24 '10 at 00:13
  • @James: Yes, it will wait for the data. – Jim Mischel Nov 24 '10 at 00:14
  • @James: Yes, ReadString returns the entire string, not just a part of it. But it doesn't "wait" for anything. It just reads the length and the bytes that make up the string from the stream. If there are less bytes then indicates by the length prefix, it will throw an Exception. – dtb Nov 24 '10 at 00:15
  • [facepalm] Thanks guys.. Ive been reading all the 'reader' documentation for hours now trying to figure out where the extra data is coming from and its the write process that has had me chasing ghosts! Will mark this as the answer when I can in a few min.. – James Nov 24 '10 at 00:17