45

I'm reading a file into a byte array in chunks and sending it over the network via a POST request to a webserver. It's not anything complicated, I've done it before using this exact same code. This time, I noticed that my images are looking really odd when they get to the server, so I decided to look at the byte array being sent and the one being received just to make sure it was the same. It's not. On the java sending side the byte array contains negative numbers. On the C# receiving side, there are no negative numbers.

The first 15 bytes on the receiving side (C#)

137
80
78
71
13
10
26
10
0
0
0
13
73
72
68

Those same bytes but on the sending side (java)

-119
80
78
71
13
10
26
10
0
0
0
13
73
72
68

All of the non-negative numbers are the same, and the -119 isn't the only negative number, they are all over. I did notice that -119 and 137 are 256 apart and wondered if that has something to do with it.

The code I'm using to read the image (java)

public static byte[] readPart(String fileName, long offset, int length) throws FileNotFoundException, Exception
{
    byte[] data = new byte[length];
    File file = new File(fileName);
    InputStream is = new FileInputStream(file);
    is.skip(offset);
    is.read(data,0,data.length);
    is.close();
    return data;
}

The code I'm using to write the data (c#)

    private void writeFile(string fileName, Stream contents)
    {
        using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
        {
            int bufferLen = 65000;
            byte[] buffer = new byte[bufferLen];
            int count = 0;
            while ((count = contents.Read(buffer, 0, bufferLen)) > 0)
            {
                fs.Write(buffer, 0, count);
            }
            fs.Close();
        }
        contents.Close();
    }

I don't know if that is something that always happens and I just never noticed it before or if it is something that decided to go horribly wrong. What I do know is that this code worked before for something very similar and that it's not working now.

If anyone has any suggestions or an explanation I would really appreciate it.

EDIT: The reason my images were looking odd is how I was calling the readPart method.

byte[] data = FileUtilities.readPart(fileName,counter,maxFileSize);//counter is the current chunk number

How I should have been calling it

byte[] data = FileUtilities.readPart(fileName,counter*maxFileSize,maxFileSize);//the current chunk * cuhnksize for the offset...

Thanks everyone, I'm significantly less confused now :)

6
  • Just tried making all the bytes positive before they were sent using data[i] = (byte)Math.abs((int)data[i]); That doesn't work, it tells me the image is corrupt at that point. Commented Mar 7, 2012 at 21:35
  • Is it only the first byte of the whole file, or the first byte of every chunk? Commented Mar 7, 2012 at 21:37
  • 3
    Java's byte is signed, so it's not possible to have 137 stored in a byte. Maybe your problem comes from this? Commented Mar 7, 2012 at 21:37
  • Signed and unsigned bytes should have nothing to do with the images showing up oddly. Are you sure the entire image is sent over? Write the result image to file and compare the bytes. Commented Mar 7, 2012 at 21:40
  • @CookieOfFortune More than the entire image is sent over... I just found that out. When my max chunk size is large enough to send the entire file, it's fine. When it's not, for example 1024, I send a total of 135168 bytes where I only want to send 134762. The 135168 is the file size being saved as well, so I suspect that is what is happening with the strange images Commented Mar 7, 2012 at 21:59

5 Answers 5

49

In Java, byte is a signed value (using two's complement to encode negative values), so what you see it correct if unexpected by most people.

To convert a byte to an unsigned int value, use b & 0xff

Sign up to request clarification or add additional context in comments.

2 Comments

I can confirm it works, and kind of understand it. Also adding + 256 to that -25 (in my case 0xE7) actually works as well. Still, I don't fully grasp what's the actual problem here. Can you explain a bit more what the bit shifting does?
(byte)0xE7 + 256 converts the signed byte to int (which still gives you -25) and then adds (int)256. To fully understand what is going on, you must first understand that everything is just a bit pattern and you are giving those bits meaning by defining math operations in certain ways to encode real things. With that knowledge, you can read the linked article to understand what the bit pattern means. The next step is then to understand Java's type widening rules: docs.oracle.com/javase/specs/jls/se7/html/jls-5.html
34

Java doesn't have unsigned bytes; all bytes are treated as signed. That's all.

All that really matters is how you think of the bytes, since you rarely ever actually need to do comparisons on bytes. The only significant difference is that they print out as signed, as you've discovered.

If you like, you can use e.g. Guava's UnsignedBytes utilities to view Java bytes as unsigned, but there's really not much practical difference.

2 Comments

And in C#, byte is unsigned and sbyte is signed.
From Java 1.8, the Byte class has gained some static methods to get the unsigned value of the byte: * one for int Byte.toUnsignedInt(byte), * one for long Byte.toUnsignedLong(byte)
14

As a further explanation, assume you have 137 as an unsigned byte. That is represented as:

1000 1001

This binary value, when expressed as a signed two's complement number, turns out to be -119. (-128 + 9)

Any unsigned byte values over 128 will be affected by the difference since the left-most bit is used in this way by the two's complement scheme.

1 Comment

Finally I was able to validate if the bytes are correct when debugging. I have -16, which in turn is 240 as ubyte (240 - 256) = - 16
5

Maybe it has something to do with the fact that Java's byte is signed (range -128 to 127) while C#'s is unsigned (0 to 255) :). The information is the same in binary, it's just interpreted differently.

2 Comments

for why Java has negative numbers is byte? what are they useful??
chiperortiz I assume it is just in order to match the convention of all its other primitive binary types. I wish they had enabled signed and unsigned types but here we are, I think that would be a major change at this point. You just have to be careful when dealing with "negative" values that might get automatically up-casted to larger types in Java because it will sign-extend them instead of prefixing with zeros, which can lead to bugs if you weren't expecting that.
3

The range of byte is from -128 to 127, so if you try to assign a byte 128, it will cycle around and the result will be -128.

System.out.println("Max val = " + Byte.MAX_VALUE);   //prints: Max val = 127
System.out.println("Min val = " + Byte.MIN_VALUE);   //prints: Min val = -128

System.out.println("(byte)137 = " + (byte)137);      //prints: (byte)137 = -119
System.out.println("(byte)128 = " + (byte)128);      //prints: (byte)128 = -128
System.out.println("(byte)-129 = " + (byte)-129);    //prints: (byte)-129 = 127

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.