Byte Arrays and ColdFusion (Part II)

The function below creates an empty byte array of a specified length in ColdFusion. Why is this useful? You usually need byte arrays for reading from Java InputStreams, so if you are working with Java streams in ColdFusion (trying to embed all your Java code in CFScript so as to not require a jar file installation) the function below will come in very handy:


<cffunction name="getByteArray" access="private" returnType="binary" output="no">
<cfargument name="size" type="numeric" required="true"/>
<cfset var emptyByteArray =
createObject("java", "java.io.ByteArrayOutputStream").init().toByteArray()/>
<cfset var byteClass = emptyByteArray.getClass().getComponentType()/>
<cfset var byteArray =
createObject("java","java.lang.reflect.Array").newInstance(byteClass, arguments.size)/>
<cfreturn byteArray/>
</cffunction>

17 Responses to Byte Arrays and ColdFusion (Part II)

  1. Roland Collins says:

    Actually, using CF, the StringBuffer approach can be done very simply, and without instantiating multiple java objects. Try these on for size.Easy to read:sb = createObject(“java”, “java.lang.StringBuffer”);sb.init(RepeatString(” “, 1024));byteArray = sb.toString().getBytes();One Liner!:byteArray = createObject(“java”, “java.lang.StringBuffer”).init(RepeatString(” “, 1024)).toString().getBytes();

  2. Christian’s goal is to do this without having to create a large string and then convert it to an array.I’m sure there’s an easier way to get a Class object for the type “byte” tho’…

  3. That was my first approach, but as Sean says, I wanted a way to do it without creating strings. The performance difference between the two approaches is noticeable. And the only other way to get the class for a byte is to do “Byte.TYPE”, but I don’t think that works in CFScript.

  4. Roland Collins says:

    Good points on performance! How about this then (with Christians help):byteClass = createObject(“java”, “java.lang.Byte”);byteClass.Init(javaCast(“string”, “1”));byteArray = createObject(“java”,”java.lang.reflect.Array”).newInstance(byteClass.TYPE, 1024);

  5. Roland Collins says:

    Or does the minor string instance in the constructor have enough of a performance hit to cripple this?I’m curious, as we’re doing this for one of our apps and these methods will all be a huge improvement on what we used.

  6. Ok, I think this is probably going to be the most efficient approach:<cfset var byteClass = createObject("java", "java.lang.Byte").TYPE/><cfset var byteArray = createObject("java","java.lang.reflect.Array").newInstance(byteClass, arguments.size)/>I haven’t done any timing, but my money would be on the code above.Christian

  7. Roland Collins says:

    One more comment, then I’m done, I promise! ;)I discovered you can just throw a 1 in there instead of the javacast – CF finds the byte constructor!byteClass = createObject(“java”, “java.lang.Byte”);byteClass.Init(1);byteArray = createObject(“java”,”java.lang.reflect.Array”).newInstance(byteClass.TYPE, 1024);Thanks for you inspiration in pursuing this – it has lead to a nice perfomance gain in a section of our application!

  8. Meban says:

    Thee best bloggg

  9. D.Ross.Blog says:

    Changing (novell) passwords over LDAP w/ CFMX

    If you are in an environment that uses Novell Directory services, you may have enabled some of your web apps to perform authentication against the novell user accounts, typically using the CFLDAP tag. This works great, and it’s a great…

  10. Joshua says:

    After you get byteArray, how do you populate it with binary data (ie: binary from file)?

  11. Mike Rankin says:

    I have a string that I have converted to hex ( 8244b42e39393939393503d1) that I’m converting to a binary object and sending to another site. Here is a snippet of the code I used to populate the object:str1 = this.hexBatch;strLen = str1.length().toString();fileLen = toString(strLen/2);byteClass = createObject(“java”, “java.lang.Byte”).TYPE;refArray = createObject(“java”,”java.lang.reflect.Array”);this.b = refArray.newInstance(byteClass,fileLen);for (i = 1; i lt strLen; i = i + 2) {byteVal = inputBaseN(mid(this.hexBatch,i,2),16);refArray.setByte(this.b,javaCast(“int”,i/2),createObject(“java”, “java.lang.Byte”).init(byteVal));}It may not be the best implementation, but it seems to work.

  12. Christian Murphy says:

    If anyone else is wondering how to populate the byte array, you may want to check java.lang.System and, in particular, the arraycopy function.In my case, I wanted a byte array made up of the contents of src1 and src2, both byte arrays. After constructing the array using the reflection technique described on this page, I was able to do the following:sys.arraycopy(src1, 0, b, 0, src1len);sys.arraycopy(src2, 0, b, src1len, src2len);Thanks very much for making this page available, by the way, it really helped me.

  13. Victor Moore says:

    Christian do you have a full exemple of the arraycopy? If you do, please email it to me if you don’t mind. i am trying to resize an array by copying it to a new one but it doesn’t want to work. No specific error is generated by CFMX either.Thanks

  14. volki says:

    I have a jsp code like that;what is the coldfusion equivalent of this jsp code:

  15. volki says:

    // This JSP will save the request Input Steam into a file.String fileOut = “C:\\aaa\\bbb\\ccc”;try{ServletInputStream in = request.getInputStream();byte[] line = new byte[1024];int bytes = 0;FileOutputStream fileOutS = new FileOutputStream(fileOut);while(0 <(bytes = in.read(line))){fileOutS.write(line,0, bytes);}fileOutS.close();fileOutS = null;out.println(“SUCCESSFUL : Upload Stream Saved to \”” + fileOut + “\”.”);}catch(Exception e){out.println(“ERROR : Exception \”” + e.getMessage() + “\” Occured.”);}

  16. Nathan Given says:

    I searched google to figure out how to read a byte array and your blog came up.You see, I have a problem. I’m trying to graph the number of people that have logged in my site daily for the past year. I’m using MySQL and storing LOGIN_ID, LOGIN_DATE (as DATETIME), and USERNAME.However, I can’t figure out how to use cfchartseries with my query to graph the number of logins per day and have it display nicely. This is because my LOGIN_DATE in the database is DATETIME, not DATE. I try stripping of the time portion using a mysql function in my select query:SELECT COUNT(LOGIN_ID) as login_count, DATE_FORMAT(DATE,’%Y-%m-%d’) as ldateFROM book_loginsGROUP BY ldateORDER BY ldate ASC;But when I cfdump that query, ldate is binary (you can see the dump if you go to my url).When I try to convert it to a string (#ldate#) the error says that a byte array can’t be converted to a string.If you look at the binary data in the dump carefully, you’ll notice it is just an integer that increments every day… so, if I could just parse out the last 5 digits, I could use DateAdd to convert it to date and voila! I’d be able to graph my stuff.So, how do I parse out the last 5 digits of my byte Array?Thanks!–Nathan