tags:

views:

109

answers:

3

Hi all,

When reading two dates from a binary file I'm seeing the error below:

"The output char buffer is too small to contain the decoded characters, encoding 'Unicode (UTF-8)' fallback 'System.Text.DecoderReplacementFallback'. Parameter name: chars"

My code is below:

static DateTime[] ReadDates()
{
    System.IO.FileStream appData = new System.IO.FileStream(
       appDataFile, System.IO.FileMode.Open, System.IO.FileAccess.Read);

    List<DateTime> result = new List<DateTime>();
    using (System.IO.BinaryReader br = new System.IO.BinaryReader(appData))
    {
        while (br.PeekChar() > 0)
        {
            result.Add(new DateTime(br.ReadInt64()));
        }
        br.Close();
    }
    return result.ToArray();
}

static void WriteDates(IEnumerable<DateTime> dates)
{
    System.IO.FileStream appData = new System.IO.FileStream(
       appDataFile, System.IO.FileMode.Create, System.IO.FileAccess.Write);

    List<DateTime> result = new List<DateTime>();
    using (System.IO.BinaryWriter bw = new System.IO.BinaryWriter(appData))
    {
        foreach (DateTime date in dates)
            bw.Write(date.Ticks);
        bw.Close();
    }
}

What could be the cause? Thanks

+2  A: 

The problem is that you're using PeekChar - that's trying to decode binary data as if it were a UTF-8 character. Unfortunately, I can't see anything else in BinaryReader which allows you to detect the end of the stream.

You could just keep calling ReadInt64 until it throws an EndOfStreamException, but that's pretty horrible. Hmm. You could call ReadBytes(8) and then BitConverter.ToInt64 - that would allow you to stop when ReadBytes returns a byte array with anything less than 8 bytes... it's not great though.

By the way, you don't need to call Close explicitly as you're already using a using statement. (That goes for both the reader and the writer.)

Jon Skeet
Hi Jon, thanks for the help. Could I trouble you for a snippet of coding showing how I'd use ReadBytes(8) and BitConverter.ToInt64? Many thanks
Jamie
@Jamie: I'm afraid I haven't got time right now, but basically loop round, calling ReadBytes(8) and checking whether the resulting byte array has 8 bytes in it or not. If not, you're done. If it has, call BitConverter.ToInt64 to get the long value to then construct the date from.
Jon Skeet
Many thanks Jon
Jamie
+1  A: 

I think Jon is correct that it's PeekChar that chokes on the binary data.

Instead of streaming the data, you could get it all as an array and get the values from that:

static DateTime[] ReadDates() {
  List<DateTime> result = new List<DateTime>();
  byte[] data = File.ReadAllBytes(appDataFile);
  for (int i = 0; i < data.Length; i += 8) {
    result.Add(new DateTime(BitConverter.ToInt64(data, i)));
  }
  return result;
}
Guffa