Google is coming out with Google Knol (Knowledge) which is exactly what Wikipedia is all about. Read on
http://googleblog.blogspot.com/2007/12/encouraging-people-to-contribute.html
My Views on ColdFusion, Java and related technologies
Google is coming out with Google Knol (Knowledge) which is exactly what Wikipedia is all about. Read on
http://googleblog.blogspot.com/2007/12/encouraging-people-to-contribute.html
I have been using my new laptop at work (my old one crashed at MAX) for two weeks and its been pretty good. Not because the laptop is something extraordinary, its because I installed the latest versions of all the softwares and plugins I use. And the most pleasant part of it is - it has been completely ads free. I did not notice it earlier but once I landed up on sys-con's site to read some article and I was pleasantly surprised to find no irritating video ad there. For a moment, I thought that may be sys-con has grown up but that was just for a moment :-). The snapshot shows it all.
IE
Firefox
Its actually a firefox plugin adblock plus that does it automatically. The most interesting thing was that it even removed google text ads. Its interesting because we have always seen Google promoting firefox and firefox as a browser closer to Google. So now a firefox plugin that blocks google adsense and in turn hurts Google revenue is certainly not going to go well with Google. It will be interesting to see how Google plays it.
So how exactly does adblock plus block the ads? Gecko engine - the engine underneath Firefox, uses a content policy which decides which content should be loaded and which should not. Adblock defines its own policy which gets added to the browser's policy. It comes with a predefined huge collection of filters and if the url to be loaded matches any of that, it does not let the browser make a request for it. For google adsense, the url contains 'pagead2' which you can see in the adblock preference below.
Its also going to hurt many bloggers as lot of them earn substantially from ads and mainly adsense. Even my blog page contains adsense but I dont mind adblock plus as I haven't yet earned anything from it anyway. I'm loving it. :-)
Today, Andy reported a similar issue but this time it was for jpeg images. In both the cases, performance hit is huge and it does not happen with all the images.
I spent a significant amount of time debugging it today and it turns out that the reason for both the issues are same - there is something special about these images and that is colorspace. All these images actually had a different colorspace than what java imaging uses. Because of this, when we need the pixel values of image to print it on pdf (by calling BufferedImage.getRGB()), it tries to convert this colorspace to RGB colorspace and that is very very costly. That is where the entire time goes. So how do you fix it? I opened all the images in an image editor and saved it again. This time it got saved in standard RGB colorspace and the time taken to create the pdf got reduced from 110 sec to 1.5 seconds. That is huge!!! Isn't it? But can you control all the images over the web? NO.. right? Read on.. there is more to this story.
A little bit of looking up on web pointed me to this Sun bug which is the exact same bug which we were hitting. Thankfully it got fixed in mustang i.e JDK1.6 which ColdFusion8 uses by default. But hey wait a second.. Didn't Andy say that he is seeing it on ColdFusion 8? why do we still see this happening when it is fixed in JDK1.6? It appears that this bug was fixed only in core JDK api but not in JAI (Java advanced imaging) codecLib that ColdFusion 8 uses. So what do we do now? You can do either of these two
You should keep in mind that codecLib libraries are native libraries which are meant to increase the java imaging performance. So disabling it might degrade the performance of CFImage somewhere. Also keep in mind that removing this jar or disabling codecLib will not result into any loss of functionality - it just means that all image operations will be pure java.
There is another related Sun's bug which I thought might be useful to you. Image loading might get very slow if the server is running in debug mode. Your server is running in debug mode if you see something like this in your jvm.config or VM startup option.
This bug got introduced in JDK1.6 and does not exist on 1.5. So make sure that you are not running the server in debug mode.-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
I had heard about people not getting images in the generated pdf but this one was something new and spooky. Yesterday Andy Matthews posted it on cf-talk where he says that for his content, though a pdf containing 15 pages gets created but only the first page has some content and rest of the pages are blank. I ran his code on my machine and sure enough it was happening. All the content including text and image on all the pages except the first page was gone. So what was wrong? I simplified his code and here is a simple example which you can try.
In the generated pdf you will see only "Text Outside div". Spooky.. isn't it? The reason it happened was because of css style 'overflow:auto'. The rendering engine used by CFDocument underneath does not handle overflow:auto and it simply ignores the content in the div. The weird part is - it considers that content for all rendering calculations including page number and page break calculation.<cfdocument format="pdf">
Text Outside div
<div style="width:300px;overflow:auto;">
This is text inside the div. Will it show up?
</div><br>
</cfdocument>
Something you should watch out for if you use css styles in cfdocument. A workaround for the time being is not to use overflow:auto style. So modifying the above code like this will make it work.
<cfdocument format="pdf">
Text Outside div
<div style="width:300px;">
This is text inside the div. Will it show up?
</div><br>
</cfdocument>
ColdFusion team is working to get ColdFusion 8 working on 64 Bit platforms(Windows, Linux and Leopard). If you are interested and want to participate in the testing of early releases of 64 Bit support on ColdFusion 8 on these platforms, please enroll yourself for prerelease program here.
JRun 4 updater 7 got released last week and is publicly available for download. It now supports a host of new platforms, includes upgrades to existing software components and fixes for many critical bugs.
Some of the important platform support include
Another important reason why you might want this is - a very significant performance improvement in web clustering. Check out the detailed release notes here.
Wow ! What an incredible week it was. A week that saw the largest ever MAX, a week that saw the largest get together of ColdFusion community, a week that saw the best ever visibility of CF at MAX general sessions, a week that saw U2's Bono (err.. his fake??) having fun at a tech conference like MAX and a week that saw lot of cool and amazing Adobe technologies shaping up.
It also had moments of a Hollywood thriller for me. I was presenting a session on "Leveraging ColdFusion for AIR application". My first session was on Tuesday, 2nd October at 4 o'clock and at around 2 o'clock my laptop crashed and after that it just refused to boot up. Luckily I had the backup of my ppt and some demo files and hence I decided to use Sanjeev's (Pdf and compiler guy in the CF team) laptop to make the presentation. I just had one and half hour and I needed to setup everything back on his machine - install the air runtime, air sdk, cfeclipse, copy all my files etc and keep the setup ready to run whatever demos I was left with. To add to this, somehow there was no Internet available in the conference area - So where to get AIR runtime and SDK from? Sanjeev suggested that may be AIR guys might have it and so we ran across to the AIR park to get those on my flash drive. I can't tell you what those one and half hour were like :-). I barely managed to get the presentation ready in time and thankfully the presentation went well.
As if this was not enough, the adventure continued for the repeat session as well. No this time the laptop didn't crash.. but this time I could not find Sanjeev so that I could take the laptop from him. I just had half an hour left for the session and I did not have any laptop. And I didn't even have the patience for setting it all up once again on another laptop. Finally found him just 15 minutes before my session while he was chatting with BEA guys. phew..
Anyway, here is my presentation and some of the demo files if you are interested to take a look at that. I could not upload it earlier as I got a temporary laptop just yesterday. I will upload the flex part of demo in a day or two.
If you were there at MAX, you must have seen Hemant talking about ColdFusion and AIR at sneak peek. Though this was just a prototype, it surely gives an idea what can be done in CF for air apps. It would be great if you can share what exactly or what else would you like to see in ColdFusion to help you build AIR application easily. Thoughts??
We have released a cumulative hotfix for CFDocument related issues in ColdFusion 8. Bugs being addressed in this hotfix are
You can download the hotfix directly from here. You would need to extract the hotfix jar from the downloaded zip file and apply that jar.
Till ColdFusion 7, it was not possible to upload a large file. The server could not handle uploading a file of probably anything more than 300-400 MB. And on top of that, if there are multiple people trying to upload large files simultaneously to the server, only thing that you can do is to pray :-)
You might wonder and I agree with you, that its a huge limitation. So why was it this way ? Well.. that was because the server had to keep the entire uploaded file in the memory. Whoa.. Why the heck does the server need to keep the entire uploaded file in memory? - For a single reason of serving the function GetHttpRequestData(). As you know, this function returns a 'struct' containing the metadata for the Http request that comes to the server. Since this struct also includes request body, and the uploaded file is part of the request, the file has to be retained in the memory in order to honor this function.
With ColdFusion 8, we have removed the limitation on file upload size. So now you can upload files of any size without causing any issue with the server. I have successfully tried with 5 GB file because that was the biggest I could get hold of but you can absolutely upload files of any size. ColdFusion nicely handles it, reads it the way it should without requiring much memory.
But hey, hold on a sec.. What about the function GetHttpRequestData()? Wasn't that the reason for this limitation in the first place? Well, the function GetHttpRequestData() works perfectly fine except in this one case - In the multipart request, i.e; request in which a file is uploaded - "content" in the returned struct will be empty. If you need to get the uploaded file content in memory, you can always read the uploaded file and keep it in memory. So that should not be much we are asking for. Are we?
If in case, you absolutely want the content from GetHttpRequestData() and file upload size is of no concern to you, we allow you to revert back to ColdFusion 7 behaviour. All you need to do for this is to set the Java system property "coldfusion.markResetForMultiPart" to "true" and you are back to the old behavior.
Though this hack in Gmail has been known for a while, I read about it today and found it interesting enough to share it. As Amit decribes in his post, GMAIL lets you create unlimited number of aliases for your gmail id and you can then give these aliases on other websites without worrying about spams. The trick is to use '+' addressing!
As he says, gmail ignores anything between '+' and '@' in the email address. So a mail sent to paris.hilton+model@gmail.com or paris.hilton+celebrity@gmail.com will all go to paris.hilton@gmail.com. In the received mail, "To" will still point to the original id to which it was sent which makes it easy to create spam filters based on the 'To' address. If used intelligently, you also get to know which site leaks your address and creates SPAM. So, if I have to give my mail id to any website xyz.com, I can give 'mymailid+xyz@gmail.com'. If I get the spam with 'to' address as mymailid+xyz@gmail.com, I get to know that its xyz.com that had leaked the id and creates spam. Pretty cool..
I can't even count the number of times I have seen this error while QA folks were running webservices regressions for ColdFusion 8. Everytime, someone was running webservices tests on a J2EE configuration they used to get an error :
coldfusion.jsp.CompilationFailedException: Errors reported by Java compiler:
....
class file has wrong version 49.0, should be 48.0
I saw the same error posted in the public forum where the user had deployed ColdFusion 8 on JRun with JDK1.5 and was trying to invoke webservice. And hence this blog entry :-)
This error comes because of incompatibility between the tools.jar and the JVM version. ColdFusion 8 ships Java 1.6's tools.jar (you will find it in cfusion/lib) which is of course incompatible with any other JDK/JRE version. You will see the same behavior with ColdFusion 7 as well, if you run it on a JVM other than 1.4. So the rule of thumb is - if ColdFusion is running on a JVM version other than the shipped one, you must ensure that the tools.jar is in synch. In short, you will need to copy JDK's tools.jar to cfusion/lib.
Today someone posted on ColdFusion forum regarding this problem where cffeed was not able to handle a particular URL and it was throwing an error. The URL which he tried was http://movies.msn.com/rss/topcelebs and it failed with an error
"Unable to read the source URL.
unknown compression method"
The reason it happens is - The URL returns the response in gzip compressed format only. So when ColdFusion sent a request to this URL and asked for uncompressed data, it could not get anything and hence it was unable to read it. A simpe workaround for this is to use cfhttp to fetch the content, write to a temporary file and then use the cffeed tag to read this file. Important thing to keep in mind here is to set an additional header in the cfhttp tag using cfhttpparam to indicate that it can accept compressed data as well.
Here is the modified code where it first tries cffeed with the URL. If that fails, then it tries to use cfhttp to fetch the content and writes to a temporary file and then uses it in cffeed.
<cfset tempDir=GetTempDirectory()>
<cfset tempFile = GetTempFile(tempDir, "myfeed")>
<cfset tempFileName = GetFileInfo(tempFile).name><cftry>
<cffeed action="read" source="http://movies.msn.com/rss/topcelebs" name="feedInStruct" >
<cfcatch any>
<cfhttp url="http://movies.msn.com/rss/topcelebs" path="#tempDir#" file="#tempFileName#">
<cfhttpparam type="header" name="Accept-Encoding" value="compress,gzip,deflate">
</cfhttp>
<cffeed action="read" source="#tempFile#" name="feedInStruct" >
</cfcatch>
</cftry>
<cfif FileExists(tempFile)>
<cfset FileDelete(tempFile)>
</cfif>
<cfdump var="#feedInStruct#">
If you use lot of CFC inside your ColdFusion application, I am sure you would have come across a situation where you would need to know whether the object is an instance of a particular CFC. This is specially needed when you have components extending other component or you are passing the objects around. ColdFusion 8 introduces a new function IsInstanceOf to do exactly the same. It becomes even more useful after we have interfaces in ColdFusion. And the icing on the cake is that it works even with java objects which means that you can use this function to find out if a particular object is of a particular java class type.
Here is how the function looks.
IsInstanceOf(object, typeName)
where typeName is name of the component/Interface or fully qualified java class name.
It returns 'true' if
Here is an example
Intf.cfc<cfinterface>
<cffunction name = "foo">
</cffunction>
</cfinterface>
Comp.cfc
<cfcomponent implements="Intf">
<cffunction name = "foo">
<cfoutput>In method foo</cfoutput>
</cffunction>
</cfcomponent>
test.cfm
<cfset obj = CreateObject("Component", "Comp")>
<cfoutput>java object is of type String : #IsInstanceOf(javaobj, "java.lang.String")#</cfoutput><br>
<!--- Create a Java object --->
<cfset javaObj = CreateObject("java", "java.lang.StringBuffer")>
<cfoutput>object is of type Comp : #IsInstanceOf(obj, "Comp")#</cfoutput><br>
<cfoutput>object is of type Intf : #IsInstanceOf(obj, "Intf")#</cfoutput><br>
<cfoutput>java object is of type StringBuffer : #IsInstanceOf(javaobj, "java.lang.StringBuffer")#</cfoutput><br>
I am not kidding. There was a recent study done by Queensland University of Technology, Australia which said that printers are hazardous and can cause sever illness including cancer ! Check out the report here.
I am glad to see the ColdFusion community so excited with CF 8 performance. We got very encouraging response regarding the performance in our pre-release forums and we are thankful to everyone who gave such invaluable feedbacks. Though people started seeing a very good performance gain in their application on ColdFusion 8, we never talked about the performance benchmark numbers until CFUnited 2007, where Ben showed the performance numbers for ColdFusion 8. No wonder this is the #1reason in Top 8 reasons why you want ColdFusion 8 :-).
Extracting performance up to this extent was not an easy task. We analyzed nearly 2.4 million lines of real life CF application code, to zero-in on the most commonly used tags and functions. Main challenge was after that - analyze the generated java code for all the tags, change the compiler to generate more optimized code, run it through profiler and optimize CF engine for each of the tags and functions and their various combinations. And this went on and on in many many iterations. Overall it was real fun :-)
I still remember the most exciting moment when I ran the load test for CFC, after I had made some code changes, and the result was freaking unbelievable. It looked too good to be true and I was literally running around with the code changes to run it on other machines and verify it . That one small change gave nearly 6x gain :-). It is not that the CF7 code was inefficient or poorly written. It was only matter of extracting juices as much as possible and putting some smart intelligence.
Check out the ColdFusion 8 performance whitepaper which talks in much detail about the performance numbers for different areas, the methodology used for benchmarking etc. Manju Kiran, who was my QA-buddy for most of the features I worked on, did a tremendous job in setting up and running the benchmark and creating the meat of this wonderful document (and of course keeping me on toes).
Though it got pretty late, I was able to sneak-in this change in ColdFusion 8. ListToArray() now takes an additional optional argument "includeEmptyElements", which if 'true' will include the empty elements of list into the array. Default is of course 'false'. It also takes care of empty elements at the end of list and multiple delimiters. Here is how the function looks
Lets take a look at couple of examples to see it working
<cfset list = "a,b,,c, ,d,,">
<cfset arr = ListToArray(list, ',', true)>
<cfdump var="#arr#">
Here is another example.
<cfset list = "one,/$/,six">
<cfset arr = listToArray(list, ",$/",true)>
<cfdump var="#arr#">
The output for which looks like this
Though we wanted to, there was just not enough time to make similar change in all the list functions for CF 8. Something for CF 9 :-)
As you all know, CFDocument tag is used to easily create pdf or flashpaper documents from HTML/CFML content. ColdFusion 8 has added lot of enhancements to it and in this post we will talk about those enhancements.
1. Bookmark : You can create bookmarks for each section of the pdf using "bookmark" attribute. The bookmark created is of only one level and its name is set to the documentsection's name. Here is a sample code for creating pdf with bookmarks.
<cfdocument format="PDF" bookmark="yes">
<cfdocumentsection name="Introduction">
<h3>Introduction</h3>
<p>The introduction goes here.</p>
</cfdocumentsection>
<cfdocumentsection name="Chapter 1">
<h3>Chapter 1: Getting Started</h3>
<p>Chapter 1 goes here.</p>
</cfdocumentsection>
<cfdocumentsection name="Chapter 2">
<h3>Chapter 2: Building Applications</h3>
<p>Chapter 2 goes here.</p>
</cfdocumentsection>
<cfdocumentsection name="Conclusion">
<h3>Conclusion</h3>
<p>The conclusion goes here.</p>
</cfdocumentsection>
</cfdocument>
3. Content from URL : Though this was added in 7.0.2, I think it makes sense to add here because it was not there in 7. :-) Have you ever created or wanted to create a pdf from a web page? If yes, then the new attribute "src" in cfdocument and cfdocumentsection tag makes it very easy to do this. Here is an example to do this.
4. Basic Authentication : If the CFDocument body contains a resource (e.g; image or URL) that is protected with basic authentication, ColdFusion 7 can not retrieve it and it was one of the reason for getting "red-x" for images. (See my old post on this). ColdFusion 8 addresses this by adding these two attributes to cfdocument and cfdocumentsection tag.
5. User Agent : There are some cases where the web server is configured to allow requests only from a certain set of browsers (User agents to be precise) to prevent spiders and bots from overloading the server. In ColdFusion 7, when CFDocument creates a URLConnection for an image, it sends a "User-Agent" header, that looks like "User-Agent:Java/1.4.2_07", in the HTTP request. If the web server does not recognize "Java" user-agent, it returns a status code of 404 (resource not found) and hence the images can not be displayed. ColdFusion 8 adds a new attribute "user-agent" to address this.
6. PDF name : When a pdf generated by cfdocument is sent to the browser and you try to save it, the browser will prompt with the cfm name for the pdf which is generally not desirable. With ColdFusion 8, you can provide the appropriate name in "saveAsName" attribute of cfdocument.
Here is a sample code for the same.
<cfdocument format="pdf" saveAsName="mypdf">
<p>This is a PDF document.</p>
</cfdocument>
This attribute helps reducing the load from the server so that the same web server thread can now serve user request instead of serving local images to CFDocument. This also addresses some of the "missing image" problems which I mentioned here. Here is a sample code using this attribute.
<cfdocument format="PDF" localUrl="true">
<table>
<tr>
<td>bird</td>
<td><image src="images/bird.jpg"></td>
</tr>
<tr>
<td>Rose</td>
<td><image src="images/rose.jpg"></td>
</tr>
</table>
</cfdocument>
9. Dynamic header and footer : CFDOCUMENT scope variables can now be used in expressions inside <cfdocumentitem> which makes it possible to have dynamic header and footers. You can now build logic for header/footer content based on the page number. Here is a sample code which prints section title if the page is even and prints the page no otherwise. Below is a code snippet which creates a dynamic header.
<cfdocumentitem type="header">
<cfif (cfdocument.currentpagenumber mod 2) is 0>
<cfoutput>#sectionTitle#</cfoutput>
<cfelse>
<cfoutput>#cfdocument.currentpagenumber# of #cfdocument.TOTALPAGECOUNT#</cfoutput>
</cfif>
</cfdocumentitem>
<cfset myfile = FileOpen("C:\cfunited_notes.txt")>
<cfdump var="#myfile#">
<cfloop condition="Not FileIsEOF(myfile)">
<cfset line = FileReadLine(myfile)>
<cfoutput>#line#</cfoutput><br>
</cfloop>
<cfset FileClose(myfile)>
1. Reading/writing big files - Since <cffile> is a tag, it can only perform one-shot operations. So, to read, it has to read everything in one shot and to write, you have to provide the entire content and that means that <cffile> will have to keep the entire content in memory. It is not of much concern if the file size is just few KBs but as the size increases beyond 100 kb or when it reaches few megs, it can really hurt. It would create a memory crunch on the server and if the load is high and there are many read/write happening simultaneously with large files, it can even lead to OutOfMemory error in server. Apart from creating memory crunch, it will also slow down the server because VM would need to allocate/deallocate larger chunk of memory which would lead to larger and frequent Garbage Collection cycle. At this point, you might ask, why would I ever read or write such a big file? Well I can think of few
The new I/O is based on the same philosophy that is used in other languages i.e;
Step 1 : Open a file : Here is the function to open a file
FileOpen(filepath [,mode] [,charset]) -> fileobjectBoth mode and charset here and optional. Mode can be "read", "readBinary", "write" or "append"
"read" mode, which is default, is used to read a text file and hence any read operation will give you text data from it. When the file is a text file, you can also optionally specify the charset of the file. So if the file contains UTF-8 or UTF-16 characters (or characters from any other charset), you need to specify it while opening the file.
"readBinary" is used to read a binary file and hence any read operation will give you the binary data i.e byte array.
"write" mode will open the file in write mode which means that if the file already exists, it will be overwritten.
"append" mode, as the name suggests, will open the file in append mode which means that any write operation on that file object will write it at the end of file.
FileOpen function returns you a handle to the native file and you need to use this handle for all further read/write operation. Of course you should keep in mind that you can not perform "read" operation on a file handle that was opened in "write" mode and vice versa.
Step 2 : Do Read/Write operations : Once you get the handle to file object, you can perform multiple read/write operations using this handle. There are several functions to do that.
2A. Read Operation :
i) FileRead(fileobj, no of character/bytes to read) : This provides you a way to read a chunk of data (say 1 kb at a time) from the file at a time. Since you only read a chink of data at a time, it does not create memory crunch on the server. Since this is read operation, file must have been opened in "read" or "readBinary" mode. Depending on which mode the file was opened, this function will return the text or binary data read. One thing to note here - If the data remaining is less than the requested size, this method will return you only the remainign data. i.e if 100 character are remaining in the file being read, and you request for 1000 characters, it will return you 100 characters only.
ii) FileReadLine(fileobject) - This reads one line from the text file. To call this method, the file must have been opened in "read" mode.
Both these read operations can be called multiple times until you reach end of the file. One the end of file has reached, any further read call will result into an "EndOfFile" error. So in order to avoid this error, you should always check whether you have reached the end of file. And the function to do that is
FileIsEOF(fileobj) : Just to be more clear, EOF here stands for "End of File". This function will return true if the end of file has been reached otherwise will return false.
Here are few examples of reading content from file
Read 1 kb binary data at a time.
<cfscript>
myfile = FileOpen("c:\temp\song.mp3", "readbinary");
while (! FileIsEOF(myfile)) { // continue the loop if the end of file has not reached
x = FileRead(myfile, 1024); // read 1 kb binary data
...// process this binary data..
}
</cfscript>
<cfscript>
myfile = FileOpen("c:\temp\myfile.txt", "read");
while (! FileIsEOF(myfile)) { // continue the loop if the end of file has not reached
x = FileReadLine(myfile); // read a line
...// process this line..
}
</cfscript>
<cfscript>
infile = FileOpen("c:\temp\input.txt", "read");
outfile = FileOpen("C:\temp\result.txt", "write");
while (! FileIsEOF(infile)) { // continue the loop if the end of file has not reached
x = FileReadLine(infile); // read a line
data = processLine(x);
FileWriteLine(outfile, data);
}
</cfscript>
FileClose(fileobj)What if you don't close the file object? Well, that file will remain locked by the server as long as the file is open, and no other process can modify/rename or delete that file.
<cfscript>
infile = FileOpen("c:\temp\input.txt", "read");
outfile = FileOpen("C:\temp\result.txt", "write");
while (! FileIsEOF(infile)) { // continue the loop if the end of file has not reached
x = FileReadLine(infile); // read a line
data = processLine(x);
FileWriteLine(outfile, data);
}
FileClose(infile);
FileClose(outfile);
</cfscript>
New attributes in cfloop for reading file :
"file" - path of the file to read
"characters" - no of characters to read in one iteration.
<cfloop file="c:\temp\myfile.txt" index="line">
<cfoutput>#line#</cfoutput> <!--- or do whatever with the line --->
</cfloop>
<cfloop file="c:\temp\myfile.txt" index="line" from=10 to=20>
<cfoutput>#line#</cfoutput> <!--- or do whatever with the line --->
</cfloop>
<cfloop file="c:\temp\myfile.txt" index="line" to="10">
<cfoutput>#line#</cfoutput> <!--- or do whatever with the line --->
</cfloop>
<cfloop file="c:\temp\myfile.txt" index="chars" characters="1000">
<cfset x=chars>
<!--- do whatever with the characters --->
</cfloop>
<cffunction name="getMimeType">
<cfargument name="filepath">
<cfset var urlConn = createObject("java", "java.net.URLConnection")>
<cfset var fileobj = fileopen(filepath, "readbinary")>
<!--- just read the first 20 characters of the file as thats sufficient --->
<cfset var bytes = fileread(fileobj, 20)>
<cfset var istream = createObject("java", "java.io.ByteArrayInputStream").init(bytes)>
<cfset fileobj.close()>
<cfreturn urlConn.guessContentTypeFromStream(istream)>
</cffunction>
<cffunction name="GetImageType">
<cfargument name="filepath">
<cfset var mimetype = getMimeType(filepath)>
<cfset var imagetype="">
<cfif not isDefined("mimetype")>
<cfthrow message="Not an Image file">
</cfif>
<cfswitch expression="#mimetype#">
<cfcase Value="image/gif">
<cfset imagetype="gif">
</cfcase>
<cfcase Value="image/x-bitmap">
<cfset imagetype="bmp">
</cfcase>
<cfcase Value="image/png">
<cfset imagetype="png">
</cfcase>
<cfcase Value="image/jpeg">
<cfset imagetype="jpeg">
</cfcase>
<cfcase Value="image/jpg">
<cfset imagetype="jpeg">
</cfcase>
<cfdefaultcase>
<cfthrow message="Not an Image file">
</cfdefaultcase>
</cfswitch>
<cfreturn imagetype>
</cffunction>
<cfset filepath = "C:\temp\test.jpg">
<cfoutput>#GetImageType(filepath)#</cfoutput>
You should note that I used the new File IO function added in ColdFusion 8 using which I can read as many no of bytes from the file as I want. No more reading the entire file into memory.
More extensive post on File IO functions coming next !
guessContentTypeFromName(String name) - that simply checks the extension of the file name specified and gets the mime type from a static map it maintains. This can be very useful in many scenarios. The map it uses is quite extensive and contains almost all the mime types.
But this has a problem. What if some one has renamed a gif to jpg? This method will say that the file is a jpg image whereas it was a gif.
Thankfully there is another method in the same class which can address this problem.
guessContentTypeFromStream(InputStream stream) - which reads the stream, takes a look at the initial bits of the file and uses that to determine the file type.
This method does a check for the following mime types :-
- application/java-vm
- application/x-java-serialized-object
- text/html
- application/xml
- image/gif
- image/x-bitmap
- image/x-pixmap
- image/png
- image/jpeg
- image/jpg
- image/vnd.fpx
- audio/basic
- audio/x-wav
Incidently Charlie had also talked about the same some time back here and he mentions another problem with this approach. The array that is returned after split method is read only and you can not modify this array.
In order to address both these, I had to write this UDF which I guess many people would have written anyways..
<cfscript>
function list2Array(list)
{
var endCommaCount = 0;
var i = 0; var c = "";
var stringForSplit = ""; var retList=""; var arr = "";
for(i=len(list); i > 0; i--)
{
c = list.charAt(i-1);
if(c == ',')
endCommaCount++;
if( c != ',' && c != ' ')
break;
}
retlist = ArrayNew(1);
if(i != 0)
{
stringForSplit = left(list, i);
arr = stringForSplit.split("\s*,\s*");
for(i = 1; i <= ArrayLen(arr); i++)
ArrayAppend(retList, arr[i]);
}
for(i = 0; i < endCommaCount; i++)
ArrayAppend(retList, "");
return retList;
}
</cfscript>
<cfscript>
function list2Array(list)
{
var i = 0;
var retlist = ArrayNew(1);
var arr = list.split(",", -1);
for(i = 1; i <= ArrayLen(arr); i++)
ArrayAppend(retList, arr[i]);
return retList;
}
</cfscript>
<cfset cflist = "a,b,,c,,d, ,">
<cfset cfarr1 = ListToArray(cflist)>
<cfset ArrayAppend(cfarr1, "END")>
<cfset cfarr2 = List2Array(cflist)>
<cfset ArrayAppend(cfarr2, "END")>
With CF Function : <cfdump var="#cfarr1#" format="text">
With UDF : <cfdump var="#cfarr2#" format="text">
array - Top 6 of 6 rowsWith UDF :
1) a
2) b
3) c
4) d
5)
6) END
array - Top 9 of 9 rows
1) a
2) b
3) [empty string]
4) c
5) [empty string]
6) d
7) [empty string]
8) [empty string]
9) END
<cfset cflist="a,b,,c,,,d">
<cfset cfarr1 = ListToArray(cflist)><cfset cfarr2 = cflist.split(",")>
<cfset cfarr2 = cflist.split(",", -1)>
<cfdump var="#cfarr1#">
<cfdump var="#cfarr2#">
<cfscript>
for(i=1; i <= ArrayLen(cfarr2); i++)
{
writeoutput("Element #i# : #cfarr2[i]# <br>");
}
</cfscript>
URL url = new URL(someurlstring)
URLConnection conn = url.openConnection();
String encoding = new sun.misc.BASE64Encoder().encode("username:password".getBytes());
conn.setRequestProperty ("Authorization", "Basic " + encoding);
InputStream in = conn.getInputStream()
...
Authenticator.setDefault(new MyAuthenticator());
....
public class MyAuthenticator extends Authenticator
{
protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication ("username", "password");
}
}
import java.net.*;
public class MyAuthenticator extends Authenticator
{
private String user;
private String passwd;
public MyAuthenticator(String user, String passwd)
{
this.user = user;
this.passwd = passwd;
}
protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(user, passwd.toCharArray());
}
}
<cfif not IsDefined("Application.authenticator")>
<!--- Do initializations --->
<cfset authenticator= createObject("java", "java.net.Authenticator")>
<cfset myauthenticator = createObject("java", "MyAuthenticator").init("username", "password")>
<cfset authenticator.setDefault(myauthenticator)>
<cfset Application.authenticator=myauthenticator>
</cfif>
<cfset mylist="jan,feb,mar,apr,may,jun,jul,sep,oct,nov,dec">
<cfloop from="1" to=#ListLen(mylist)# index="i">
<cfset month = ListGetAt(mylist, i)>
<!--- do something with this month --->
<cfoutput>#month#</cfoutput>
</cfloop>
<cfset x = ArrayNew(1)>
<cfloop from=1 to=5 index=i>
<cfset Arrayappend(x,"something")>
</cfloop>
<cfset x = CreateObject("java", "java.util.ArrayList").init(x)>
<cfset foo(x)>
<cfset foo(x)>
<cfset x[8] = "after the method call">
<cfset x[9] = "end of method call">
<cfset foo(x)>
<cfdump var="#x#">
<cffunction name="foo">
<cfargument name="arr">
<cfset ArrayAppend(arr, "from function")>
</cffunction>
<cfset sb = createObject("java", "java.lang.StringBuffer")>
<cfloop from=1 to=100 index=i>
<cfset sb.append("something")>
<cfset sb.append(i)>
</cfloop>
<cfset result=sb.toString()>
<cfset arr = ArrayNew(1)>
<cfloop from=1 to=100 index=i>
<cfset ArrayAppend(arr, "something")>
<cfset ArrayAppend(arr, i)>
</cfloop>
<cfset result=ArrayToList(arr,"")>
<cfset x = "sun,mercury,venus,earth,mars,jupiter,saturn,uranus,pluto,neptune">
<cfset y = ListSort(x,"text")>
<cfset y = ListSort("sun,mercury,venus,earth,mars,jupiter,saturn,uranus,pluto,neptune","text")>
<cfset y = ListToArray("rupesh,tom,damon,hemant,ashwin,ram,prank,sanjeev")>
<cfset z = ListToArray("dean,manju,jason,tim")>
<cfset y.addAll(z)>
<cfdump var="#y#">
<cfset y = ListToArray("rupesh,tom,damon,hemant,ashwin,ram,prank,sanjeev")>
<cfset z = ListToArray("dean,manju,jason,tim")>
<cfset y.addAll(4, z)>
<cfdump var="#y#">
<cfset y = ListToArray("rupesh,tom,damon,hemant,ashwin,ram,prank,sanjeev")>
<cfoutput>Contains Hemant: #y.contains("hemant")#</cfoutput>
<cfoutput>Index of damon : #y.indexof("damon")#</cfoutput>
<cfset y = ListToArray("rupesh,tom,damon,hemant,ashwin,ram,prank,sanjeev")>
<cfset z = ListToArray("ram,prank,rupesh")>
<cfoutput> y Contains z: #y.containsAll(z)#</cfoutput>
<cfset y = ListToArray("rupesh,tom,damon,hemant,ashwin,ram,prank,sanjeev")>
<cfset z = ListToArray("dean, manju,jason,tim")>
<cfset x = ListToArray("rupesh,tom,damon,hemant,ashwin,ram,prank,sanjeev")>
<cfoutput>x equals y : #x.equals(y)#</cfoutput>
<cfoutput>x equals z : #x.equals(z)#</cfoutput>
<cfset y = ListToArray("rupesh,tom,damon,hemant,ashwin,ram,prank,sanjeev")>
before removal <cfdump var="#y#">
<cfset z = ListToArray("ram,prank,tom")>
<cfset y.removeAll(z)>
After removal <cfdump var="#y#">