Converting byte array to string and printing out to console - c#

public void parse_table(BinaryReader inFile)
{
byte[] idstring = inFile.ReadBytes(6);
Console.WriteLine(Convert.ToString(idstring));
}
It is a simple snippet: read the first 6 bytes of the file and convert that to a string.
However the console shows System.Byte[].
Maybe I'm using the wrong class for conversion. What should I be using? It will eventually be parsing filenames encoded in UTF-8, and I'm planning to use the same method to read all filenames.

It's actually:
Console.WriteLine(Encoding.Default.GetString(value));
or for UTF-8 specifically:
Console.WriteLine(Encoding.UTF8.GetString(value));

I was in a predicament where I had a signed byte array (sbyte[]) as input to a Test class and I wanted to replace it with a normal byte array (byte[]) for simplicity. I arrived here from a Google search but Tom's answer wasn't useful to me.
I wrote a helper method to print out the initializer of a given byte[]:
public void PrintByteArray(byte[] bytes)
{
var sb = new StringBuilder("new byte[] { ");
foreach (var b in bytes)
{
sb.Append(b + ", ");
}
sb.Append("}");
Console.WriteLine(sb.ToString());
}
You can use it like this:
var signedBytes = new sbyte[] { 1, 2, 3, -1, -2, -3, 127, -128, 0, };
var unsignedBytes = UnsignedBytesFromSignedBytes(signedBytes);
PrintByteArray(unsignedBytes);
// output:
// new byte[] { 1, 2, 3, 255, 254, 253, 127, 128, 0, }
The ouput is valid C# which can then just be copied into your code.
And just for completeness, here is the UnsignedBytesFromSignedBytes method:
// http://stackoverflow.com/a/829994/346561
public static byte[] UnsignedBytesFromSignedBytes(sbyte[] signed)
{
var unsigned = new byte[signed.Length];
Buffer.BlockCopy(signed, 0, unsigned, 0, signed.Length);
return unsigned;
}

I've used this simple code in my codebase:
static public string ToReadableByteArray(byte[] bytes)
{
return string.Join(", ", bytes);
}
To use:
Console.WriteLine(ToReadableByteArray(bytes));

byte[] bytes = { 1,2,3,4 };
string stringByte= BitConverter.ToString(bytes);
Console.WriteLine(stringByte);

This is just an updated version of Jesse Webbs code that doesn't append the unnecessary trailing , character.
public static string PrintBytes(this byte[] byteArray)
{
var sb = new StringBuilder("new byte[] { ");
for(var i = 0; i < byteArray.Length;i++)
{
var b = byteArray[i];
sb.Append(b);
if (i < byteArray.Length -1)
{
sb.Append(", ");
}
}
sb.Append(" }");
return sb.ToString();
}
The output from this method would be:
new byte[] { 48, ... 135, 31, 178, 7, 157 }

For some fun with linq and string interpolation:
public string ByteArrayToString(byte[] bytes)
{
if ( bytes == null ) return "null";
string joinedBytes = string.Join(", ", bytes.Select(b => b.ToString()));
return $"new byte[] {{ {joinedBytes} }}";
}
Test cases:
byte[] bytes = { 1, 2, 3, 4 };
ByteArrayToString( bytes ) .Dump();
ByteArrayToString(null).Dump();
ByteArrayToString(new byte[] {} ) .Dump();
Output:
new byte[] { 1, 2, 3, 4 }
null
new byte[] { }

Related

C# - Can I use an array initializer to build one byte array out of another?

I'd like to use an array initializer to build one byte array out of another byte array as well as some other bytes that form a header/trailer. Basically, I'd like to do something like this:
byte[] DecorateByteArray(byte[] payload)
{
return new byte[] { 0, 1, 2, payload.GetBytes(), 3, 4, 5};
}
GetBytes() above is fictional, unfortunately.
Is there any nice/elegant way to do this? I solved this by using a BinaryWriter to write everything to a MemoryStream, and then converting this into a byte array with MemoryStream.ToArray(), but it feels kind of clunky.
The closest you could get would be:
byte[] DecorateByteArray(byte[] payload) =>
new byte[] { 0, 1, 2 }
.Concat(payload)
.Concat(new byte[] { 3, 4, 5 })
.ToArray();
That would be pretty inefficient though. You'd be better off doing something like:
static T[] ConcatArrays<T>(params T[][] arrays)
{
int length = arrays.Sum(a => a.Length);
T[] ret = new T[length];
int offset = 0;
foreach (T[] array in arrays)
{
Array.Copy(array, 0, ret, offset, array.Length);
offset += array.Length;
}
return ret;
}
(Consider using Buffer.BlockCopy too, where appropriate.)
Then call it with:
var array = ConcatArrays(new byte[] { 0, 1, 2 }, payload, new byte[] { 3, 4, 5 });
You can create a new collection that is a List<byte>, but that has an overload of Add that adds a whole array of bytes:
public class ByteCollection: List<byte>
{
public void Add(IEnumerable<byte> bytes)
{
AddRange(bytes);
}
}
This then lets you use the collection initializer for this type to supply either a single byte or a sequence of bytes, which you can then turn back into an array if you need an array:
byte[] DecorateByteArray(byte[] payload)
{
return new ByteCollection() { 0, 1, 2, payload, 3, 4, 5 }.ToArray();
}
One easy way is to break out each into parts and then concat them
byte[] DecorateByteArray(byte[] payload)
{
return new byte[] { 0, 1, 2}
.Concat(payload.GetBytes())
.Concat(new byte[] { 3, 4, 5});
}

Interview test - adding using A Recursive Algorithm c#

Below is an interview question about using recursion to add two arrays.
I can't figure it out though because it does not seem to allow any kind of index to keep track of where you are, I have been down a few roads - trying to test for null / default values in the array but because it is a byte[] type nothing worked.
Any help would be great thanks - this is not a homework question.
public AddResult UsingARecursiveAlgorithm_ValuesAreAdded(byte[] a, byte[] b)
{
var result = AddRecursive(a, b);
// Assert
return new AddResult(a, b, result);
}
e.g.
Input : { 1, 1, 1 }, { 1, 1, 1 }
Result: { 2, 2, 2 }
Input : { 1, 1, 255 }, { 0, 0, 1 }
Result: { 1, 2, 0 }
Conditions:
a & b are never null, and are always of the same length.
The algorithm should be non destructive to the inputs.
Edit: the second result is incorrect. It should be { 1,1,0 } -that's the way it was presented though.
private int carry = 0;
public byte[] AddRecursive(byte[] a, byte[] b)
{
//Start from bottom of the byte[] array
a = a.Reverse().ToArray();
b = b.Reverse().ToArray();
if (a.Length == 0) return new byte[] { };
int tempresult = a[0] + b[0] + carry;
byte[] z = new byte[]
{ (byte)(tempresult) };
carry = tempresult / (byte.MaxValue + 1);
return z.Concat(AddRecursive(a.Skip(1).ToArray(), b.Skip(1).ToArray())).ToArray();
}
//Test//
[Test]
public void Add_UsingARecursiveAlgorithm_ValuesAreAdded()
{
//First Test
byte[] expectedResult = addthisaddthat.AddRecursive(new byte[] { 1, 1, 1 }, new byte[] { 1, 1, 1 }).Reverse().ToArray();
Assert.That(expectedResult, Is.EqualTo(new byte[] { 2, 2, 2 }));
//Sec Test
expectedResult = addthisaddthat.AddRecursive(new byte[] { 1, 1, 255 }, new byte[] { 0, 0, 1 }).Reverse().ToArray();
Assert.That(expectedResult, Is.EqualTo(new byte[] { 1, 2, 0 }));
//Third Test
expectedResult = addthisaddthat.AddRecursive(new byte[] { 255, 255, 255 }, new byte[] { 255, 255, 255 }).Reverse().ToArray();
Assert.That(expectedResult, Is.EqualTo(new byte[] { 255, 255, 254 }));
}
Ok here is some rather "ugly" code that does what you want. I tried to write it for clarity rather than brevity:
static byte[] AddArray(byte[] ary1, byte[] ary2) {
System.Diagnostics.Debug.Assert(ary1.Length == ary2.Length);
if ((ary1 == null) || (ary2 == null)) {
throw new ArgumentException("Empty or null array");
}
// sum the last element
var ix = ary1.Length - 1;
var sum = (ary1[ix] + ary2[ix]);
if (sum > byte.MaxValue) {
if (ix == 0) {
throw new ArgumentException("Overflow");
}
// Add carry by recursing on ary1
var carry = (byte) (sum - byte.MaxValue);
var carryAry = new byte[ary1.Length];
carryAry[ix - 1] = carry;
ary1 = AddArray(ary1, carryAry);
}
if ((ary1.Length == 1) || (ary2.Length == 1)) {
return new byte[] { (byte) sum }; // end recursion
}
// create the remainder, elements from 0 it (len-1)
var ary1Remainder = new byte[ary1.Length - 1];
var ary2Remainder = new byte[ary2.Length - 1];
Array.Copy(ary1, 0, ary1Remainder, 0, ary1.Length - 1);
Array.Copy(ary2, 0, ary2Remainder, 0, ary2.Length - 1);
// recurse
var remainder = AddArray(ary1Remainder, ary2Remainder);
// build return array (using linq Concat)
var rv = (remainder.Concat(new byte[] { (byte) sum }));
return rv.ToArray(); // return as an array
}
This would be cleaner without all the casting and ToArray required because the values are byte[] and not IEnumerable<int>, but:
private byte[] AddRecursive(byte[] a, byte[] b) {
if (a.Length == 0) return new byte[]{};
return
new byte[] { (byte)(a[0] + b[0]) }.Concat(
AddRecursive(a.Skip(1).ToArray(), b.Skip(1).ToArray())
).ToArray();
}
Maybe your interviewer had something like this in mind:
using System;
using System.Linq;
public class Program
{
public static byte[] Add(byte[] a, byte[] b, int index = -1)
{
if (index < 0)
{
return Add((byte[])a.Clone(), b, 0);
}
if (index < a.Length)
{
Add(a, b, index + 1);
a[index] += b[index];
}
return a;
}
public static void Main(string[] args)
{
var r1 = Add(new byte[] { 1, 1, 1 }, new byte[] { 1, 1, 1 });
var r2 = Add(new byte[] { 1, 1, 255 }, new byte[] { 0, 0, 1 });
var r3 = Add(new byte[] { 0, 100, 200 }, new byte[] { 3, 2, 1 });
// Outputs: 2, 2, 2
Console.WriteLine(string.Join(", ", r1.Select(n => "" + n).ToArray()));
// Outputs: 1, 1, 0
Console.WriteLine(string.Join(", ", r2.Select(n => "" + n).ToArray()));
// Outputs: 3, 102, 201
Console.WriteLine(string.Join(", ", r3.Select(n => "" + n).ToArray()));
}
}
https://dotnetfiddle.net/UqSQb3
Note this (only partial) solution doesn't handle the carry on byte overflows, though.
'Hope this helps,

Hex to Byte Array in C# and Java Gives Different Results

First of all, sorry for the long post, I want to include all my thoughts so it's easier for you guys to find what's wrong about my code.
I want to transfer an Hex string from a C# application to a Java application. But, when I convert the same Hex value to a Byte Array on both languages, the output is different.
For instance, the same Hex value gives
[101, 247, 11, 173, 46, 74, 56, 137, 185, 38, 40, 191, 204, 104, 83, 154]
in C# and
[101, -9, 11, -83, 46, 74, 56, -119, -71, 38, 40, -65, -52, 104, 83, -102]
in Java
Here are the methods I use in C#:
public static string ByteArrayToHexString(byte[] byteArray)
{
return BitConverter.ToString(byteArray).Replace("-",""); //To convert the whole array
}
public static byte[] HexStringToByteArray(string hexString)
{
byte[] HexAsBytes = new byte[hexString.Length / 2];
for (int index = 0; index < HexAsBytes.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return HexAsBytes;
}
And the ones in Java:
public static String ByteArrayToHexString(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b: bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString().toUpperCase();
}
public static byte[] HexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
Here's an example in C#:
String hexString = "65F70BAD2E4A3889B92628BFCC68539A";
byte[] byteArray = HexBytes.HexStringToByteArray(hexString);
//Using the debugger, byteArray = [101, 247, 11, 173, 46, 74, 56, 137, 185, 38, 40, 191, 204, 104, 83, 154]
String hexString2 = HexBytes.ByteArrayToHexString(byteArray)
Console.Write("HEX: " + hexString2);
//Outputs 65F70BAD2E4A3889B92628BFCC68539A
And an example in Java:
String hexString = "65F70BAD2E4A3889B92628BFCC68539A";
byte[] byteArray = HexBytes.HexStringToByteArray(hexString);
//Using the debugger, byteArray = [101, -9, 11, -83, 46, 74, 56, -119, -71, 38, 40, -65, -52, 104, 83, -102]
String hexString2 = HexBytes.ByteArrayToHexString(byteArray);
System.out.println("HEX: " + hexString2);
//Outputs 65F70BAD2E4A3889B92628BFCC68539A
As you can see, when I do the opposite operation, the final Hex value is equal to the first one, which means the way I convert is potentially good in both languages individually. But I don't understand why the conversion from Hex to a byte array is different in both languages. I thought Hexadecimal was simply a number on another base.
Thanks for the help
Cydrick
Update
I fixed this issue by replacing the C# code with the following code:
public static string ByteArrayToHexString(sbyte[] byteArray)
{
return BitConverter.ToString(convert(byteArray)).Replace("-", ""); //To convert the whole array
}
public static sbyte[] HexStringToByteArray(string hexString)
{
byte[] HexAsBytes = new byte[hexString.Length / 2];
for (int index = 0; index < HexAsBytes.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return convert(HexAsBytes);
}
private static sbyte[] convert(byte[] byteArray)
{
sbyte[] sbyteArray = new sbyte[byteArray.Length];
for (int i = 0; i < sbyteArray.Length; i++)
{
sbyteArray[i] = unchecked((sbyte) byteArray[i]);
}
return sbyteArray;
}
private static byte[] convert(sbyte[] sbyteArray)
{
byte[] byteArray = new byte[sbyteArray.Length];
for (int i = 0; i < byteArray.Length; i++)
{
byteArray[i] = (byte) sbyteArray[i];
}
return byteArray;
}
But, when I convert the same Hex value to a Byte Array on both languages, the output is different.
All you're seeing is that bytes are signed in Java and unsigned in C#. So if you add 256 to any negative value in Java, you'll get the value shown in C#. The actual bits in the values are the same - it's just a matter of whether the top bit is treated as a sign bit or not.
EDIT: As noted in comments, if you're ever using the byte as an integer outside the debugger output, you can always use:
int someInt = someByte & 0xff;
to get the unsigned value.
Looks like this is a debugger issue only. Those negative values you're seeing in the Java debugger are the signed equivalents to the unsigned values you're seeing in the C# debugger. For example, signed byte -9 == unsigned byte 247 (notice that they always differ by 256). The data is fine.

Hash SHA1 large files (over 2gb) in C#

I`m looking for solution for hashing large file content (files may be over 2gb in 32bit os). It there any easy solution for that? Or just reading by part and loading to buffer?
Driis's solution sounds more flexible, but HashAlgorithm.ComputeHash will also accept Streams as parameters.
Use TransformBlock and TransformFinalBlock to calculate the hash block by block, so you won't need to read the entire file into memory. (There is a nice example in the first link - and another one in this previous question).
If you choose to use TransformBlock, then you can safely ignore the last parameter and set the outputBuffer to null. TransformBlock will copy from the input to the output array - but why would you want to simply copy bits for no good reason?
Furthermore, all mscorlib HashAlgorithms work as you might expect, i.e. the block size doesn't seem to affect the hash output; and whether you pass the data in one array and then hash in chunks by changing the inputOffset or you hash by passing smaller, separate arrays doesn't matter. I verified this using the following code:
(this is slightly long, just here so people can verify for themselves that HashAlgorithm implementations are sane).
public static void Main() {
RandomNumberGenerator rnd = RandomNumberGenerator.Create();
byte[] input = new byte[20];
rnd.GetBytes(input);
Console.WriteLine("Input Data: " + BytesToStr(input));
var hashAlgoTypes = Assembly.GetAssembly(typeof(HashAlgorithm)).GetTypes()
.Where(t => typeof(HashAlgorithm).IsAssignableFrom(t) && !t.IsAbstract);
foreach (var hashType in hashAlgoTypes)
new AlgoTester(hashType).AssertOkFor(input.ToArray());
}
public static string BytesToStr(byte[] bytes) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
str.AppendFormat("{0:X2}", bytes[i]);
return str.ToString();
}
public class AlgoTester {
readonly byte[] key;
readonly Type type;
public AlgoTester(Type type) {
this.type=type;
if (typeof(KeyedHashAlgorithm).IsAssignableFrom(type))
using(var algo = (KeyedHashAlgorithm)Activator.CreateInstance(type))
key = algo.Key.ToArray();
}
public HashAlgorithm MakeAlgo() {
HashAlgorithm algo = (HashAlgorithm)Activator.CreateInstance(type);
if (key != null)
((KeyedHashAlgorithm)algo).Key = key;
return algo;
}
public byte[] GetHash(byte[] input) {
using(HashAlgorithm sha = MakeAlgo())
return sha.ComputeHash(input);
}
public byte[] GetHashOneBlock(byte[] input) {
using(HashAlgorithm sha = MakeAlgo()) {
sha.TransformFinalBlock(input, 0, input.Length);
return sha.Hash;
}
}
public byte[] GetHashMultiBlock(byte[] input, int size) {
using(HashAlgorithm sha = MakeAlgo()) {
int offset = 0;
while (input.Length - offset >= size)
offset += sha.TransformBlock(input, offset, size, input, offset);
sha.TransformFinalBlock(input, offset, input.Length - offset);
return sha.Hash;
}
}
public byte[] GetHashMultiBlockInChunks(byte[] input, int size) {
using(HashAlgorithm sha = MakeAlgo()) {
int offset = 0;
while (input.Length - offset >= size)
offset += sha.TransformBlock(input.Skip(offset).Take(size).ToArray()
, 0, size, null, -24124512);
sha.TransformFinalBlock(input.Skip(offset).ToArray(), 0
, input.Length - offset);
return sha.Hash;
}
}
public void AssertOkFor(byte[] data) {
var direct = GetHash(data);
var indirect = GetHashOneBlock(data);
var outcomes =
new[] { 1, 2, 3, 5, 10, 11, 19, 20, 21 }.SelectMany(i =>
new[]{
new{ Hash=GetHashMultiBlock(data,i), Name="ByMSDN"+i},
new{ Hash=GetHashMultiBlockInChunks(data,i), Name="InChunks"+i}
}).Concat(new[] { new { Hash = indirect, Name = "OneBlock" } })
.Where(result => !result.Hash.SequenceEqual(direct)).ToArray();
Console.Write("Testing: " + type);
if (outcomes.Any()) {
Console.WriteLine("not OK.");
Console.WriteLine(type.Name + " direct was: " + BytesToStr(direct));
} else Console.WriteLine(" OK.");
foreach (var outcome in outcomes)
Console.WriteLine(type.Name + " differs with: " + outcome.Name + " "
+ BytesToStr(outcome.Hash));
}
}

Binary to Text Translation C# [duplicate]

Hi i was able to convert a ASCII string to binary using a binarywriter .. as 10101011 . im required back to convert Binary ---> ASCII string .. any idea how to do it ?
This should do the trick... or at least get you started...
public Byte[] GetBytesFromBinaryString(String binary)
{
var list = new List<Byte>();
for (int i = 0; i < binary.Length; i += 8)
{
String t = binary.Substring(i, 8);
list.Add(Convert.ToByte(t, 2));
}
return list.ToArray();
}
Once the binary string has been converted to a byte array, finish off with
Encoding.ASCII.GetString(data);
So...
var data = GetBytesFromBinaryString("010000010100001001000011");
var text = Encoding.ASCII.GetString(data);
If you have ASCII charters only you could use Encoding.ASCII.GetBytes and Encoding.ASCII.GetString.
var text = "Test";
var bytes = Encoding.ASCII.GetBytes(text);
var newText = Encoding.ASCII.GetString(bytes);
Here is complete code for your answer
FileStream iFile = new FileStream(#"c:\test\binary.dat",
FileMode.Open);
long lengthInBytes = iFile.Length;
BinaryReader bin = new BinaryReader(aFile);
byte[] byteArray = bin.ReadBytes((int)lengthInBytes);
System.Text.Encoding encEncoder = System.Text.ASCIIEncoding.ASCII;
string str = encEncoder.GetString(byteArray);
Take this as a simple example:
public void ByteToString()
{
Byte[] arrByte = { 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
string x = Convert.ToBase64String(arrByte);
}
This linked answer has interesting details about this kind of conversion:
binary file to string
Sometimes instead of using the built in tools it's better to use "custom" code.. try this function:
public string BinaryToString(string binary)
{
if (string.IsNullOrEmpty(binary))
throw new ArgumentNullException("binary");
if ((binary.Length % 8) != 0)
throw new ArgumentException("Binary string invalid (must divide by 8)", "binary");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < binary.Length; i += 8)
{
string section = binary.Substring(i, 8);
int ascii = 0;
try
{
ascii = Convert.ToInt32(section, 2);
}
catch
{
throw new ArgumentException("Binary string contains invalid section: " + section, "binary");
}
builder.Append((char)ascii);
}
return builder.ToString();
}
Tested with 010000010100001001000011 it returned ABC using the "raw" ASCII values.

Categories