4
DateTime todayDateTime = DateTime.Now;
StringBuilder todayDateTimeSB = new StringBuilder("0");
todayDateTimeSB.Append(todayDateTime.ToString("MMddyyyy"));
long todayDateTimeLongValue = Convert.ToInt64(todayDateTimeSB.ToString());
// convert to byte array packed decimal
byte[] packedDecValue = ToComp3UsingStrings(todayDateTimeLongValue); 
// append each byte to the string builder
foreach (byte b in packedDecValue)
{
    sb.Append(b); // bytes 56-60
}
sb.Append(' ', 37);

The above code takes the current date time, formats it into a long value and passes that to a method which converts it to a packed decimal format. I know that the above works since when I step though the code the byte array has the correct Hex values for all of the bytes that I am expecting.

However the above is the code I am having issues with, specifically I have researched and found that the string builder .Append(byte) actually does a ToString() for that byte. Which is altering the value of the byte when it adds it to the string. The question is how do I tell the StringBuilder to take the 'byte' as is and store it in memory without formatting/altering the value. I know that there is also a .AppendFormat() which has several overloads which use the IFormatProvider to give lots and lots of options on how to format things but I don't see any way to tell it to NOT format/change/alter the value of the data.

Picrofo Software
  • 5,475
  • 3
  • 23
  • 37
user1922299
  • 41
  • 1
  • 1
  • 3
  • 1
    `The question is how do I tell the StringBuilder to take the 'byte' as is and store it in memory without formatting/altering the value.` Well you can't really because a StringBuilder representa a mutable sequence of characters but **a byte isn't a character**. You can convert a byte to a character if you know the encoding (presumably ASCII). – Mark Byers Dec 21 '12 at 19:16

2 Answers2

10

You can cast the byte to a char:

sb.Append((char)b);

You can also use an ASCIIEncoding to convert all the bytes at once:

string s = Encoding.ASCII.GetString(packedDecValue);
sb.Append(s);
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • Many thanks! This is a real life saver. This should also prevent the conversion ton BSTR from having any issues since it is stored as an ASCII value. I could also have had the conversion utility do the cast too but I like your solution of converting to a string. – user1922299 Dec 26 '12 at 13:56
  • I used string s = Encoding.ASCII.GetString(packedDecValue). That seems to work but in some cases when we add it to string builder it still garbles the string. From the looks of things it is when we get a ASCII value in the extended ascii set, specifically the value we are having issues with is {0x01,0x99,0x0c}. It comes out as a string value from the encoding as one string but when it is added to string builder it gets converted to something else. The value from the Encoding.ASCII.GetString(packedDecValue) is "?\f", sb mangles that possibly due to the \? – user1922299 Jan 03 '13 at 17:45
  • Scratch the above, the next response which I just voted up addresses this point since 0x99 is outside of the 0x00-0x7f range the ? is stating that it is chucking the data. So for packed dec this solution will not work. – user1922299 Jan 03 '13 at 20:18
1

As noted, in a Unicode world, bytes (octets) are not characters. The CLR works with Unicode characters internally and internally represents them in the UTF-16 encoding. A StringBuilder builds a UTF-16 encoded Unicode string.

Once you have that UTF-16 string, however, you can re-encode it, using, say UTF-8 or the ASCIIEncoding. However, in both of those, code points 0x0080 and higher will not be left as-is.

UTF-8 uses 2 octets for code points 0x0080–0x07FF; 3 octets for code points 0x0800–0xFFFF and so on. http://en.wikipedia.org/wiki/UTF-8#Description

The ASCII encoding is worse: per the documentation, code points outside 0x0000–0x007F are simply chucked:

If you use the default encoder returned by the Encoding.ASCII property or the ASCIIEncoding constructor, characters outside that range are replaced with a question mark (?) before the encoding operation is performed.

If you need to send a stream of octets unscathed, you are better off using a System.IO.MemoryStream wrapped in a StreamReader and StreamWriter.

You can then access the MemoryStream's backing store via its GetBuffer() method or its ToArray() method. GetBuffer() gives you a reference to the actual backing store. However it likely contains alloated, but unused, bytes — you need to check the stream's Length and Capacity. ToArray() allocates a new array and copies the actual stream content into it, so the array reference you recieve is the correct length.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
  • Thanks for the background information. It's good to know, for my purposes encoding as ascii should work fine since all my values should be inside the ascii encoding range. However if I was doing something other than converting numbers to packed decimal it could be an issue... IE trying to store raw binary data with possible large values. – user1922299 Dec 26 '12 at 13:50
  • It appears I have ran into the code points for ASCII. Can I still use UTF-8 to encode or do I need to just scrap the use of stringbuilder entirely and use the streamreader? See comment on the current highest update. – user1922299 Jan 03 '13 at 20:12
  • Is there a way to take this memory stream/stream reader and convert the stream to a bstr? – user1922299 Jan 03 '13 at 20:33
  • Update, turns out you can't use streamwriter since it uses textwriter so you get the same issue when trying to copy a byte array to the stream using it. So, I am just using the base memory stream, converting the 'string' parts to byte arrays and just doing everything at byte level using memorystream.... Still need to convert the final byte array to a BSTR but progress has been made. – user1922299 Jan 09 '13 at 20:38