At work we have a import procedure that reads several ZIP files uploaded to us and then imports the contents of it (XML file into the database and the picture files to their corresponding folders in our web directory).
Since that process is scheduled to run several times a day, I was having locking problems when trying to move a zip file to the work folder while it was still being uploaded through FTP by the client.
I used the approach recommended by Jeff Peters on the “Directory Watcher Dangers” on Gateways issues, by adapting his function into my import process, checking the file size in a loop (below is his watcher function):
<CFFUNCTION NAME="onAdd" ACCESS="public" RETURNTYPE="string">
<CFARGUMENT NAME="CFEvent" TYPE="struct" REQUIRED="yes">
<CFSCRIPT>
thisFile = cfevent.data.filename;
fileRead = createObject("java","java.io.FileInputStream");
thisThread = CreateObject("java", "java.lang.Thread");
loopCT = 1;
while (1 EQ 1){
try {
fileRead.init(thisFile);
break;
} catch(any ecpt){
thisThread.sleep(1000);
}
incrementValue(loopCT);
if (loopCT GT 60){
fileRead.close();
return;
}
}
loopCT = 1;
while (1 EQ 1){
sizeA = fileRead.available();
thisThread.sleep(1000);
sizeB = fileRead.available();
if (sizeA EQ sizeB){
thisThread.sleep(1000);
sizeC = fileRead.available();
if (sizeC EQ sizeB){
break;
}
}
incrementValue(loopCT);
if (loopCT GT 60){
fileRead.close();
return;
}
}
fileRead.close();
</CFSCRIPT>
<CFRETURN >
</CFFUNCTION>
For some unknown to me reasons, some of the files were still locked although the test returned OK.
So, following an idea of my colleague Matt, I rewrote my test function in following way:
- Try to rename the file pre-pending the work “import-” to the filename, in a try-catch.
- If any error, that means the file is still in use, return false as status and blank as newFileName
That worked well in my tests and I just put it live.
But Matt mentioned seeing some Java method called “canWrite()” and I researched at Sun’s website, coming to the simple solution below:
<cffunction name="javaCheckFile" access="remote" returntype="Boolean">
<cfargument name="filePath" type="string" required="true" />
<cfscript>
var jFile = createobject("java", "java.io.File").init(arguments.filePath);
return jFile.canWrite();
</cfscript>
</cffunction>
I did not implemented the latter version, but in the preliminary tests it seems to work well.
I hope this information can be of use for those who love mixing Java and Coldfusion.
Ricardo, interessante este código. Porém é recomendável alertar que o método canWrite pode acarretar race condition hein? Dê uma olhada nesta explicação aqui:
http://stackoverflow.com/questions/122282/can-the-java-file-method-canwrite-support-locking
[]s
Marco
@Marco Antonio
Obrigado Marco, realmente o link que voce enviou foi muito instrutivo. Eu já havia mudado nosso approach para renomear o arquivo, pois não estava retornando a resposta correta e os arquivos ficavam bloqueados.
Abraços. Ricardo