« How Do You Like Your Documentation? | Main | Flash on My Sony Clie »
January 16, 2004
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>
Posted by cantrell at January 16, 2004 12:14 PM
Comments
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();
Posted by: Roland Collins at January 16, 2004 4:57 PM
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'...
Posted by: Sean Corfield at January 16, 2004 8:13 PM
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.
Posted by: Christian Cantrell at January 16, 2004 11:07 PM
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);
Posted by: Roland Collins at January 16, 2004 11:26 PM
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.
Posted by: Roland Collins at January 16, 2004 11:29 PM
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
Posted by: Christian Cantrell at January 16, 2004 11:38 PM
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!
Posted by: Roland Collins at January 16, 2004 11:38 PM
Thee best bloggg
Posted by: Meban at February 20, 2004 7:30 AM
After you get byteArray, how do you populate it with binary data (ie: binary from file)?
Posted by: Joshua at July 7, 2004 2:18 PM
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.
Posted by: Mike Rankin at August 11, 2004 12:39 PM
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.
Posted by: Christian Murphy at February 22, 2005 7:01 PM
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
Posted by: Victor Moore at April 4, 2005 6:39 PM
I have a jsp code like that;
what is the coldfusion equivalent of this jsp code:
Posted by: volki at May 2, 2005 4:50 AM
AUTHOR: volki
EMAIL: volkankah@yahoo.com
IP: 213.74.34.7
URL:
DATE: 05/02/2005 04:51:05 AM
Posted by: volki at May 2, 2005 4:51 AM
// 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.");
}
Posted by: volki at May 2, 2005 4:52 AM
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 ldate
FROM book_logins
GROUP BY ldate
ORDER 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
Posted by: Nathan Given at December 13, 2005 3:42 PM