Why BinaryReader.ReadDecimal() returns wrong value? - c#

I stored data type values into a file then consumes it but I get the wrong result. What do I need to do get the right result?
BinaryWriter bw = new BinaryWriter(file.OpenWrite());
string str = "Lalisa";
int num = 10;
decimal dec = 2;
bw.Write(str);
bw.Write(num);
bw.Write(dec);
bw.Close();
BinaryReader br = new BinaryReader(file.OpenRead());
Console.WriteLine(br.ReadString());
Console.WriteLine(br.ReadInt16());
Console.WriteLine(br.ReadDecimal());
br.Close();
/*
output:
Lalisa
10
131072
*/
Writer output
Note* I'm using FileInfo class for the stream.
The purpose of this is for studying I'm not trying to solve a problem for a project.

The problem is the below line
Console.WriteLine(br.ReadInt16());
You are writing a 32 bit integer, and reading only 16 bits back, causing a problem for the subsequent reads.
You should have
Console.WriteLine(br.ReadInt32());
This should fix your issue
Explanation:
The bytes are written in Little Endian format, so the 10 int and 2 decimal are written as follows. Square brackets are for marking the start and end of the int and the decimal
[0A 00 00 00] [02 00 00 00...00]
But when you read the int as just a 16 bit value, this is how you will group the bits to read
[0A 00] [00 00 02 00 00 00...00]
As you can notice, the int does not suffer in this process and is still read as 0x000A, but the decimal got shifted by 2 bytes, switching it from 0x02 to 0x020000 which is 131702 in decimal
If the format was big endian, then you would have see the int get the incorrect value of 0x00

Related

ByteArray to string then string to byte array [duplicate]

I have this code:
Int32 i1 = 14000000;
byte[] b = BitConverter.GetBytes(i1);
string s = System.Text.Encoding.UTF8.GetString(b);
byte[] b2 = System.Text.Encoding.UTF8.GetBytes(s);
Int32 i2 = BitConverter.ToInt32(b2,0);;
i2 is equal to -272777233.
Why isn't it the input value? (14000000) ?
EDIT: what I am trying to do is append it to another string which I'm then writing to file using WriteAllText
Because an Encoding class is not going to just work for anything. If a "character" (possibly a few bytes in case of UTF-8) is not a valid character in that particular character set (in your case UTF-8), it will use a replacement character.
a single QUESTION MARK (U+003F)
(Source: http://msdn.microsoft.com/en-us/library/ms404377.aspx#FallbackStrategy)
Some case it is just a ?, for example in ASCII/CP437/ISO 8859-1, but there is a way for you to choose what to do with it. (See the link above)
For example if you try to convert (byte)128 to ASCII:
string s = System.Text.Encoding.ASCII.GetString(new byte[] { 48, 128 }); // s = "0?"
Then convert it back:
byte[] b = System.Text.Encoding.ASCII.GetBytes(s); // b = new byte[] { 48, 63 }
You will not get the original byte array.
This can be a reference: Check if character exists in encoding
I can't imagine why you would need to convert a byte array to a string. It obviously doesn't make any sense. Let's say you're going to write to a stream, you could just directly write byte[]. If you need to use it in some text representation, it makes perfect sense to just convert it to a string by yourIntegerVar.ToString() and use int.TryParse to get it back.
Edit:
You can write a byte array to a file, but you are not going to "concatenate" the byte array to a string and use the lazy method File.WriteAllText because it is going to handle the encoding conversion and you will probably end up having question marks ? all over your file. Instead, Open a FileStream and use FileStream.Write to directly write the byte array. Alternatively, you can use a BinaryWriter to directly write an integer in its binary form (and also a string) and use its counterpart BinaryReader to read it back.
Example:
FileStream fs;
fs = File.OpenWrite(#"C:\blah.dat");
BinaryWriter bw = new BinaryWriter(fs, Encoding.UTF8);
bw.Write((int)12345678);
bw.Write("This is a string in UTF-8 :)"); // Note that the binaryWriter also prefix the string with its length...
bw.Close();
fs = File.OpenRead(#"C:\blah.dat");
BinaryReader br = new BinaryReader(fs, Encoding.UTF8);
int myInt = br.ReadInt32();
string blah = br.ReadString(); // ...so that it can read it back.
br.Close();
This example code will result in a file which matches the following hexdump:
00 4e 61 bc 00 1c 54 68 69 73 20 69 73 20 61 20 73 Na¼..This is a s
10 74 72 69 6e 67 20 69 6e 20 55 54 46 2d 38 20 3a tring in UTF-8 :
20 29 )
Note that BinaryWriter.Write(string) also prefix the string with its length and it depends on it when reading back, so it is not appropriate to use a text editor to edit the resulting file. (Well you are writing an integer in its binary form so I expect this is acceptable?)
You shouldn't use Encoding.GetString to convert arbitrary binary data into a string. That method is only intended for text that has been encoded to binary data using a specific encoding.
Instead, you want to use a text representation which is capable of representing arbitrary binary data reversibly. The two most common ways of doing that are base64 and hex. Base64 is the simplest in .NET:
string base64 = Convert.ToBase64String(originalBytes);
...
byte[] recoveredBytes = Convert.FromBase64String(base64);
A few caveats to this:
If you want to use this string as a URL parameter, you should use a web-safe version of base64; I don't know of direct support for that in .NET, but you can probably find solutions easily enough
You should only do this at all if you really need the data in string format. If you're just trying to write it to a file or similar, it's simplest to keep it as binary data
Base64 isn't very human-readable; use hex if you want humans to be able to read the data in its text form without extra tooling. (There are various questions specifically about converting binary data to hex and back.)
It's not working because you are using encoding backwards.
Encoding is used to turn text into bytes, and then back into text again. You can't take any arbitrary bytes and turn into text. Every character has a corresponding byte pattern, but every byte pattern doesn't translate into a character.
If you want a compact way to represent bytes as text, use base-64 encoding:
Int32 i1 = 14000000;
byte[] b = BitConverter.GetBytes(i1);
string s = Convert.ToBase64String(b);
byte[] b2 = Convert.FromBase64String(s);
Int32 i2 = BitConverter.ToInt32(b2, 0);
If your goal here is to store an integer as a string then back to an integer, unless I am missing something wouldn't the following suffice:
int32 i1 = 1400000;
string s = il.ToString();
Int32 i2 = Int32.Parse(s);
To make a long story short:
You need a encoding that maps each bytevalue to a unique char and vice versa.
A UTF8 Character can be from 1 to 4 bytes long so you wont archive that mapping, you need a more basic encoding like ASCII.
Unfortunaly the original ASCII doesnt do that, it is just a 7-bit encoding and only defines the lower 128 Codes, the upper half (extended codes) is codepage specific. To get the full range translation, you just need a complete 8-bit encoding like in codepage 437 or 850 or whatever:
Int32 i1 = 14000000;
byte[] b = BitConverter.GetBytes(i1);
string s = System.Text.Encoding.GetEncoding(437).GetString(b);
byte[] b2 = System.Text.Encoding.GetEncoding(437).GetBytes(s);
Int32 i2 = BitConverter.ToInt32(b2,0);

Replacing byte in file

I'm trying to replace certain bytes from a file with some other specific bytes, but have a problem with my binary writer replacing too many bytes. What is wrong in my code?
using (BinaryWriter bw =
new BinaryWriter(File.Open(fileName,
FileMode.Open)))
{
bw.BaseStream.Position = 0x3;
bw.Write(0x50);
}
This was supposed to change the letter "E" (hex 0x45) with the letter "P", but instead changes that byte and 3 more bytes; from "45 30 31 FF" to "50 00 00 00". I would like to keep the "30 31 FF", only change "45" to "50".
Basically you don't want or need to use BinaryWriter for this. You're calling BinaryWriter.Write(int) which is behaving exactly as documented.
Just use FileStream to write a single byte:
using (var stream = File.Open(fileName))
{
stream.Position = 3;
stream.WriteByte(0x50);
}
Simpler, easier to read (it's obviously only writing a single byte), and does what you want.
Because method Write actually write int (4 bytes). You should convert your value to byte type. bw.Write((byte)0x50);

Read input file in hex mode in C#

File Info: First 4 bytes contains number of records in the file | Next 4 bytes contain length of the first record. After first record again 4 bytes contain length of second record. The entire file is like this. So I have to read the input file and skip first 4 bytes. After that I need to read 4 bytes which will give me length of upcoming record and write out the record in string and repeat the process.
I ma not getting what I am supposed to get. For example:
For 7F CB 00 00, I should get 32715 (which I don nott need, need to skip). Next 4 bytes which is
00 D3 00 00 00 I should get 211 but I am not getting that.
Any help would be appreciated.
private void button1_Click(object sender, EventArgs e)
{
FileStream readStream;
readStream = new FileStream(singlefilebox.Text,FileMode.Open,FileAccess.Read);
BinaryReader readBinary = new BinaryReader(readStream);
byte inbyte;
inbyte = readBinary.ReadByte();
string outbyte;
while (readBinary.BaseStream.Position < readBinary.BaseStream.Length)
{
inbyte = readBinary.ReadByte();
outbyte = Convert.ToString(inbyte);
}
The first issue is with how you are doing your output. When you are generating the outbyte, it is being converted to it's decimal notation. For example, CB is converted to 203.
Change the line that generates the outbyte to the following:
outbyte = Convert.ToString(String.Format("{0:X}", inbyte));
This prints the string representation of the hexadecimal number.
See this answer for more detail about the string formatting. String.Format for Hex
The bigger issue is that you need to combine the bytes in the proper way. You need to read in each byte, shift it 8 bits, then add the next byte.
string fileName = #"..\..\TestInput.hex";
FileStream readStream;
readStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader readBinary = new BinaryReader(readStream);
byte inbyte;
string outbyte;
int value;
inbyte = readBinary.ReadByte(); // read in the value: 7F in hex , 127 in decimal
value = inbyte << 8; // shift the value 8 bits to the left: 7F 00 in hex, 32512 in decimal
inbyte = readBinary.ReadByte(); // read in the next value: CB in hex, 203 in decimal
value += inbyte; // add the second byte to the first: 7F CB in hex, 32715 in decimal
Console.WriteLine(value); // writes 32715 to the console

Coordinate Id of same card that is read by two different card readers

In a part of a software, card is read by a card reader and is allocated to an user. And in other part of this software, in a terminal by same card reader, the user card is read and fetch data from database by card serial number and etc.
In a new part of this software, there are a new terminal with a new card reader. card is read from this card reader and fetch data from database and etc.
So, now the problem is that a same card that is read by this two card readers are different in type. The first device return card id as a hexadecimal string, like this:
2E 6F 27 3F
This hexadecimal string is converted to decimal and is stored in the database. For example, the above hexadecimal string is converted to this integer:
779036479
Now, when second card reader read this same card, the card id is an array of bytes, like this for that card:
byte0: 49
byte1: 48
byte2: 53
byte3: 57
byte4: 53
byte5: 52
byte6: 56
byte7: 57
byte8: 55
byte9: 52
How can I coordinate this two serial number of same card with each other? In other words, I want to convert this array of bytes to corresponding hex code, so that this hex code is the serial number of that card that first device is return?
The card is Mifare.
The answer is that the second reader is returning ASCII encoded decimals. Your number is 1059548974. This number, encoded into hexadecimals is 3F276F2E if you use Big Endian encoding. If you use Little Endian encoding then you will get 2E6F273F which should be familiar to you.
So:
decode the returned byte array to ASCII, retrieving the string "1059548974"
convert that string to an integer using Convert.ToUInt32(str);
reverse the bytes in the integer
Probably the best way to reverse the bytes is this piece of code:
public static UInt32 ReverseBytes(UInt32 value)
{
return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
(value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
}
Its rather hard to understand just exactly what your wanting, but in the bottom you state: 'in other words, i want to convert this array of bytes to corresponding hex code'.
You can perform that operation like so:
public static string ByteArrayToString(byte[] ba)
{
StringBuilder sb = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
sb.AppendFormat("{0:x2}", b);
}
return sb.ToString();
}
Just pass in your Byte array and the result will be your hex conversion in string format.
Edit: This will probably yield the same results, but try this:
byte[ ] bytes = {0, 1, 2, 4, 8, 16, 32, 64, 128, 255 }
Console.WriteLine( BitConverter.ToString( bytes ) );

Little endian to integer

I am getting this string
8802000030000000C602000033000000000000800000008000000000000000001800000000000
and this is what i am expecting to convert from string,
88020000 long in little endian => 648
30000000 long in little endian => 48
C6020000 long in little endian => 710
33000000 long in little endian => 51
left side is the value i am getting from the string and right side is the value i am expecting. The right side values are might be wrong but is there any way i can get right side value from left??
I went through several threads here like
How to convert an int to a little endian byte array?
C# Big-endian ulong from 4 bytes
I tried quite different functions but nothing giving me value which are around or near by what i am expecting.
Update :
I am reading text file as below. Most of the data are current in text format, but all of the sudden i am getting bunch of GRAPHICS info, i am not sure how to handle it.
RECORD=28
cVisible=1
dwUser=0
nUID=23
c_status=1
c_data_validated=255
c_harmonic=0
c_dlg_verified=0
c_lock_sizing=0
l_last_dlg_updated=0
s_comment=
s_hlinks=
dwColor=33554432
memUsr0=
memUsr1=
memUsr2=
memUsr3=
swg_bUser=0
swg_dConnKVA=L0
swg_dDemdKVA=L0
swg_dCodeKVA=L0
swg_dDsgnKVA=L0
swg_dConnFLA=L0
swg_dDemdFLA=L0
swg_dCodeFLA=L0
swg_dDsgnFLA=L0
swg_dDiversity=L4607182418800017408
cStandard=0
guidDB={901CB951-AC37-49AD-8ED6-3753E3B86757}
l_user_selc_rating=0
r_user_selc_SCkA=
a_conn1=21
a_conn2=11
a_conn3=7
l_ct_ratio_1=x44960000
l_ct_ratio_2=x40a00000
l_set_ct_ratio_1=
l_set_ct_ratio_2=
c_ct_conn=0
ENDREC
GRAPHICS0=8802000030000000C602000033000000000000800000008000000000000000001800000000000
EOF
Depending on how you want to parse up the input string, you could do something like this:
string input = "8802000030000000C6020000330000000000008000000080000000000000000018000000";
for (int i = 0; i < input.Length ; i += 8)
{
string subInput = input.Substring(i, 8);
byte[] bytes = new byte[4];
for (int j = 0; j < 4; ++j)
{
string toParse = subInput.Substring(j * 2, 2);
bytes[j] = byte.Parse(toParse, NumberStyles.HexNumber);
}
uint num = BitConverter.ToUInt32(bytes, 0);
Console.WriteLine(subInput + " --> " + num);
}
88020000 --> 648
30000000 --> 48
C6020000 --> 710
33000000 --> 51
00000080 --> 2147483648
00000080 --> 2147483648
00000000 --> 0
00000000 --> 0
18000000 --> 24
Do you really literally mean that that's a string? What it looks like is this: You have a bunch of 32-bit words, each represented by 8 hex digits. Each one is presented in little-endian order, low byte first. You need to interpret each of those as an integer. So, e.g., 88020000 is 88 02 00 00, which is to say 0x00000288.
If you can clarify exactly what it is you've got -- a string, an array of some kind of numeric type, or what -- then it'll be easier to advise you further.

Categories