Convert float to its binary representation (using MemoryStream?) - c#

I'd like to convert a given float into its binary representation. I tried to write the float value into a MemoryStream, read this MemoryStream byte by byte and convert the bytes into their binary representation. But every attempt failed.
"Can't read closed stream" (but I only closed the writer)
For test purposes I simply wrote an integer (I think four bytes in size) and the length of the MemoryStream was 0, when I didn't flush the StreamWriter, and 1, when I did.
I'm sure there is a better way to convert floats to binary, but I also wanted to learn a little bit about the MemoryStream class.

You can use BitConverter.GetBytes(float) or use a BinaryWriter wrapping a MemoryStream and use BinaryWriter.Write(float). It's not clear exactly what you did with a MemoryStream before, but you don't want to use StreamWriter - that's for text.

Using BitConverter, not MemoryStream:
// -7 produces "1 10000001 11000000000000000000000"
static string FloatToBinary(float f)
{
StringBuilder sb = new StringBuilder();
Byte[] ba = BitConverter.GetBytes(f);
foreach (Byte b in ba)
for (int i = 0; i < 8; i++)
{
sb.Insert(0,((b>>i) & 1) == 1 ? "1" : "0");
}
string s = sb.ToString();
string r = s.Substring(0, 1) + " " + s.Substring(1, 8) + " " + s.Substring(9); //sign exponent mantissa
return r;
}

Dotnetfiddle
BitConverter.GetBytes(3.141f)
.Reverse()
.Select(x => Convert.ToString(x, 2))
.Select(x => x.PadLeft(8, '0'))
.Aggregate("0b", (a, b) => a + "_" + b);
// res = "0b_01000000_01001001_00000110_00100101"
Couldn't resist to use a "small" LINQ Query.
Works with double too.

You might have run into a pitfall when using StreamWriter, as the following code shows:
// Write the float
var f = 1.23456f;
var ms = new MemoryStream();
var writer = new StreamWriter(ms);
writer.Write(f);
writer.Flush();
// Read 4 bytes to get the raw bytes (Ouch!)
ms.Seek(0, SeekOrigin.Begin);
var buffer = new char[4];
var reader = new StreamReader(ms);
reader.Read(buffer, 0, 4);
for (int i = 0; i < 4; i++)
{
Console.Write("{0:X2}", (int)buffer[i]);
}
Console.WriteLine();
// This is what you actually read: human readable text
for (int i = 0; i < buffer.Length; i++)
{
Console.Write(buffer[i]);
}
Console.WriteLine();
// This is what the float really looks like in memory.
var bytes = BitConverter.GetBytes(f);
for (int i = 0; i < bytes.Length; i++)
{
Console.Write("{0:X2}", (int)bytes[i]);
}
Console.ReadLine();
If you expect only 4 bytes to be in the stream and read those 4 bytes, everything looks fine at first sight. But actually the length is 7 and you have read only the first 4 bytes of the text representation of the float.
Comparing that to the output of the BitConverter reveals that using StreamWriter is not the correct thing here.

To answer your first question: In .Net, when you close/dispose a reader/writer, the underlying stream is also closed/disposed.

Related

C# How to fix loss of data during file to binary to string to binary conversion

I read a file as binary, convert to hex string, convert back to binary, and write to a new file.
I expect a duplicate, but get a corrupted file.
I have been trying different ways to convert the binary into the hex string but can't seem to retain the entire file.
byte[] binary1 = File.ReadAllBytes(#"....Input.jpg");
string hexString = "";
int counter1 = 0;
foreach (byte b in binary1)
{
counter1++;
hexString += (Convert.ToString(b, 16));
}
List<byte> bytelist = new List<byte>();
int counter2 = 0;
for (int i = 0; i < hexString.Length/2; i++)
{
counter2++;
string ch = hexString.Substring(i*2,2);
bytelist.Add(Convert.ToByte(ch, 16));
}
byte[] binary2 = bytelist.ToArray();
File.WriteAllBytes(#"....Output.jpg", binary2);
Counter 1 and counter 2 should be the same count, but counter 2 is always about 10% smaller.
I want to get a duplicate file output that I could have transferred around via that string value.
Converting byte 10 will give a single char, and not 2 characters. Your convert back method (logically) build on 2 chars per byte.
this case works
byte[] binary1 = new byte[] { 100 }; // convert will result in "64"
and this case fails
byte[] binary1 = new byte[] { 10 }; // convert will result in "a"
I quick fixed your code, by padding with a "0" in case of a single char.
so working code:
byte[] binary1 = new byte[] { 100 };
string hexString = "";
int counter1 = 0;
foreach (byte b in binary1)
{
counter1++;
var s = (Convert.ToString(b, 16));
// new
if (s.Length < 2)
{
hexString += "0";
}
// end new
hexString += s;
}
List<byte> bytelist = new List<byte>();
int counter2 = 0;
for (int i = 0; i < hexString.Length / 2; i++)
{
counter2++;
string ch = hexString.Substring(i * 2, 2);
var item = Convert.ToByte(ch, 16);
bytelist.Add(item);
}
byte[] binary2 = bytelist.ToArray();
Please note, your code could use some refactoring, e.g. don't string concat in a loop and maybe check the Single Responsibility Principle.
Update, got it fixed, but there are better solutions here: How do you convert a byte array to a hexadecimal string, and vice versa?

Binary reading from string

I'm writing little decoder. User enter string (hex) that program should decode.
My problem is that int value is not the same as inputed, therefore I don't know how should I advance after reading binary. Am I missing point on how to read binary ?
string input = "0802";
byte[] arr = Encoding.Default.GetBytes(input);
using (MemoryStream stream = new MemoryStream(arr))
{
using (BinaryReader reader = new BinaryReader(stream))
{
int a = reader.ReadInt32();
Console.WriteLine(a);
//output: 842020912
}
}
This is correct. You read 4 bytes from the string so they are interpreted as 4 bytes of your int.
If you check the hex value of your "incorrect" number 842020912 it will give you 0x32303830 and reading every byte as ASCII gives "2080".
The order is reversed as you are reading the value as little-endian.
You are doing it the hard way. I using Bytes but can modify for 1in16, or int32 very easily. :
string input = "0802";
List<byte> bytes = new List<byte>();
for (int i = 0; i < input.Length; i += 2)
{
bytes.Add(byte.Parse(input.Substring(i, 2), System.Globalization.NumberStyles.HexNumber));
}

IOStream operator<< Conversion from C++ to C#

I am trying to convert some old C++ code to C# and having difficulty in understanding what the following code does and how can it be converted into C#.
ifstream fin;
fin.open(file, ios::nocreate);
if (!fin)
{
m_iErrorNumber = 1567;
num = 0.0;
}
else
{
for (int x = 0; x < count; x++)
{
fin >> num; // <==== THIS LINE IS PROBLEM!!
}
};
fin.close();
The C++ Standard Library overloads the bitshift operators (<< and >>) to mean "write to stream" and "read from stream", respectively. In this case, fin is a file stream; fin >> num means to read from the file (until the next whitespace character), parse the data to match the format of the variable num (an integer), and store it into num.
This has probably slightly different semantics from the C++ code, but should be relatively similar:
IEnumerable<string> ReadWhiteSpaceSeparated(string filename)
{
using(var lines = File.ReadLines(filename))
{
return lines.SelectMany(line => line.Split(new []{' ','\t', '\r', '\n'}, StringSplitOptions.RemoveEmptyEntries));
}
}
IEnumerable<string> ReadDoubles(string filename)
{
return ReadWhiteSpaceSeparated(filename)
.Select(s => double.Parse(s, CultureInfo.InvariantCulture));
}
Then you can read count doubles from a file with ReadDoubles(filename).Take(count)
In this situation the >> operator is streaming data from the file stream into what I assume is a double. Here is how the code would look in C# (change the 8 to a 4 if you're just using a float):
using (var stream = System.IO.File.Open(file, System.IO.FileMode.Open))
{
var data = new byte[8]; // temp variable to hold byte data from stream
for(var x = 0; x < count; ++x)
{
stream.Read(data, 0, 8);
num = System.BitConverter.ToDouble(data, 0); // convert bytes to double
// do something with num
}
}

How to speed up writing large byte array to afile?

I need to convert a hex string to byte array, then have to write it to a file. The below code gives 3 seconds of delay. Below hex is an hex string of length 1600. Is there any other way to make this faster ?
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 5000; i++)
{
FileStream objFileStream = new FileStream("E://CRec Correcting Copy//Reader//bin//Debug//Files//Raw Data//a123.txt", FileMode.Append, FileAccess.Write);
objFileStream.Seek(0, SeekOrigin.End);
objFileStream.Write(stringTobyte(hex), 0, stringTobyte(hex).Length);
objFileStream.Close();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
stringTobyte is a metho to convert the hex string to byte array.
public static byte[] stringTobyte(string hexString)
{
try
{
int bytesCount = (hexString.Length) / 2;
byte[] bytes = new byte[bytesCount];
for (int x = 0; x < bytesCount; ++x)
{
bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16);
}
return bytes;
}
catch
{
throw;
}
}
Please tell me where the delay is happening ?
You're thinking way to complicated. First of all, no need for your custom function to convert it to a byte array. System.Text.UTF8Encoding.GetBytes(string) will do that for you! Also, no need for streams here, have a look at File.WriteAllBytes(string, byte[]) method.
Then it should look like this:
System.IO.File.WriteAllBytes("E://CRec Correcting Copy//Reader//bin//Debug//Files//Raw Data//a123.txt", new System.Text.UTF8Encoding().GetBytes(hex));
or a multiline version, if you insist:
string filePath = "E://CRec Correcting Copy//Reader//bin//Debug//Files//Raw Data//a123.txt";
System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
byte[] bytes = encoder.GetBytes(hex);
System.IO.File.WriteAllBytes(filePath, bytes);
Wow. For first do this:
objFileStream.Write(stringTobyte(hex), 0, stringTobyte(hex).Length);
byte[] bytes = stringTobyte(hex);
objFileStream.Write(bytes , 0, bytes.Length);

BitConverter.ToString() in reverse? [duplicate]

This question already has answers here:
How do you convert a byte array to a hexadecimal string, and vice versa?
(53 answers)
Closed 8 years ago.
I have an array of bytes that I would like to store as a string. I can do this as follows:
byte[] array = new byte[] { 0x01, 0x02, 0x03, 0x04 };
string s = System.BitConverter.ToString(array);
// Result: s = "01-02-03-04"
So far so good. Does anyone know how I get this back to an array? There is no overload of BitConverter.GetBytes() that takes a string, and it seems like a nasty workaround to break the string into an array of strings and then convert each of them.
The array in question may be of variable length, probably about 20 bytes.
Not a built in method, but an implementation. (It could be done without the split though).
String[] arr=str.Split('-');
byte[] array=new byte[arr.Length];
for(int i=0; i<arr.Length; i++) array[i]=Convert.ToByte(arr[i],16);
Method without Split: (Makes many assumptions about string format)
int length=(s.Length+1)/3;
byte[] arr1=new byte[length];
for (int i = 0; i < length; i++)
arr1[i] = Convert.ToByte(s.Substring(3 * i, 2), 16);
And one more method, without either split or substrings. You may get shot if you commit this to source control though. I take no responsibility for such health problems.
int length=(s.Length+1)/3;
byte[] arr1=new byte[length];
for (int i = 0; i < length; i++)
{
char sixteen = s[3 * i];
if (sixteen > '9') sixteen = (char)(sixteen - 'A' + 10);
else sixteen -= '0';
char ones = s[3 * i + 1];
if (ones > '9') ones = (char)(ones - 'A' + 10);
else ones -= '0';
arr1[i] = (byte)(16*sixteen+ones);
}
(basically implementing base16 conversion on two chars)
You can parse the string yourself:
byte[] data = new byte[(s.Length + 1) / 3];
for (int i = 0; i < data.Length; i++) {
data[i] = (byte)(
"0123456789ABCDEF".IndexOf(s[i * 3]) * 16 +
"0123456789ABCDEF".IndexOf(s[i * 3 + 1])
);
}
The neatest solution though, I believe, is using extensions:
byte[] data = s.Split('-').Select(b => Convert.ToByte(b, 16)).ToArray();
If you don't need that specific format, try using Base64, like this:
var bytes = new byte[] { 0x12, 0x34, 0x56 };
var base64 = Convert.ToBase64String(bytes);
bytes = Convert.FromBase64String(base64);
Base64 will also be substantially shorter.
If you need to use that format, this obviously won't help.
byte[] data = Array.ConvertAll<string, byte>(str.Split('-'), s => Convert.ToByte(s, 16));
I believe the following will solve this robustly.
public static byte[] HexStringToBytes(string s)
{
const string HEX_CHARS = "0123456789ABCDEF";
if (s.Length == 0)
return new byte[0];
if ((s.Length + 1) % 3 != 0)
throw new FormatException();
byte[] bytes = new byte[(s.Length + 1) / 3];
int state = 0; // 0 = expect first digit, 1 = expect second digit, 2 = expect hyphen
int currentByte = 0;
int x;
int value = 0;
foreach (char c in s)
{
switch (state)
{
case 0:
x = HEX_CHARS.IndexOf(Char.ToUpperInvariant(c));
if (x == -1)
throw new FormatException();
value = x << 4;
state = 1;
break;
case 1:
x = HEX_CHARS.IndexOf(Char.ToUpperInvariant(c));
if (x == -1)
throw new FormatException();
bytes[currentByte++] = (byte)(value + x);
state = 2;
break;
case 2:
if (c != '-')
throw new FormatException();
state = 0;
break;
}
}
return bytes;
}
it seems like a nasty workaround to break the string into an array of strings and then convert each of them.
I don't think there's another way... the format produced by BitConverter.ToString is quite specific, so if there is no existing method to parse it back to a byte[], I guess you have to do it yourself
the ToString method is not really intended as a conversion, rather to provide a human-readable format for debugging, easy printout, etc.
I'd rethink about the byte[] - String - byte[] requirement and probably prefer SLaks' Base64 solution

Categories