I thought it was fixed, but now it’s doing the same thing again.
I pasted in Stefan’s code just in case I mistyped or something, and it no longer works.
New file, wrote to it once before OK., but now after error before closing the file, I get the “already open” error no matter what I do using my code or Stephan’s. Trashed the file - still same thing. This is getting weird.
OK., it works … Never noticed Finder do this before …
When I rewrote a text file before, I could see the update immediately in the file preview. This time however, that did not happen until I backed out of the folder, came back to it, and then the file preview showed the update. And it continues to update each time.
Not that it’s extremely important, but does anyone know why that happened?
I have seen this in the past. i.e. where you trash a file that was opened with ‘open for access’. Can’t remember what was the way to close it, but there was an easy trick to it. Let me think about it.
Use a handler to write to files - one that has a proper error-handler.
------------------------------------------------------------------------------------
--» writeFile()
------------------------------------------------------------------------------------
-- Task: Write to a file as a specific data-type.
-- dMod: 2012/10/26 20:00
------------------------------------------------------------------------------------
on writeFile(srcData, targetFile, startPosition, dataType)
try
set fileRef to open for access targetFile with write permission
if startPosition = 0 then
set eof of fileRef to 0
end if
write srcData to fileRef as dataType starting at startPosition
close access fileRef
on error errMsg number errNum
try
close access fileRef
end try
error "Error in handler: writeFile of library: gen.lib" & return & return & errMsg
end try
end writeFile
------------------------------------------------------------------------------------
--» writeUTF8()
------------------------------------------------------------------------------------
-- Task: Write text to a file and overwrite any content.
-- dMod: 2012/10/26 20:00
------------------------------------------------------------------------------------
on writeUTF8(_text, _file)
try
if _file starts with "~/" then
set _file to POSIX path of (path to home folder as text) & text 3 thru -1 of _file
end if
set fRef to open for access _file with write permission
set eof of fRef to 0
write _text to fRef as «class utf8»
close access fRef
on error e number n
try
close access fRef
on error e number n
error "Error in writeUTF8() handler!" & return & return & e
end try
end try
end writeUTF8
------------------------------------------------------------------------------------
Yes, as everyone has written, It’s better to write safe code. The thing is, sometimes you get into these situations and don’t know how to exit from it and the best way to do it as DJ wrote is to quit the app. If you are ever stuck, then force quit the app.
Man, I was sure there was a way to close the file by AppleScript. Still thinking about that.
BTW, this is an old problem when using the read/write scripting addition.
I think I was writing an example script by hand (no libs) for someone who preferred posix paths, and I had forgotten the exact syntax for write. So I looked it up in Script Debugger and saw the reference for to:
to required any the file reference number, alias, or file reference of the file to write to
File Reference caught my eye, and it occurred to me that I hadn’t tested in many years what formats it would tolerate ” so I made the example script into a test routine.
set testFldr to ((path to home folder as text) & "test_directory:TEST_FOLDER:")
try
alias testFldr
on error
do shell script "mkdir -p " & quoted form of (POSIX path of testFldr)
delay 0.1
end try
do shell script "open " & quoted form of (POSIX path of testFldr)
delay 1
set testHFSPath to testFldr & "test_file_1.txt"
set testPosixPath to (POSIX path of testFldr) & "test_file_2.txt"
set testPosixHomePath to "~/test_directory/TEST_FOLDER/test_file_3.txt"
set testPosixFile to POSIX file (POSIX path of testFldr & "test_file_4.txt")
writeMe("Test_File_01_HFS_Path", testHFSPath)
delay 0.2
writeMe("Test_File_02_Posix_Path", testPosixPath)
delay 0.2
writeMe("Test_File_03_Posix_Home_Path", testPosixHomePath)
delay 0.2
writeMe("Test_File_04_Posix_File", testPosixFile)
on writeMe(_text, _file)
try
set fileHandle to open for access _file with write permission
write _text to fileHandle as «class utf8»
close access fileHandle
on error e
try
close access fileHandle
end try
e
"" --» Stub for break-point in Script Debugger
end try
end writeMe
I was delighted to find out that Posix Paths were supported and disappointed that home-based-Posix-Paths were not, but the latter was an easy fix.
Well you shouldn’t close the file by reference Chris and should use StefanK’s example as I have mentioned earlier. If opening the file causes an error no file descriptor will be returned. So the rule is that In the error block you always close the file by using it’s path, never by it’s descriptor.
The AE framework did get some new features a few OS X versions back. As an scripting addition writer myself I don’t need to take posix files into consideration, the AE framework does that for me. It’s therefore not really a open for access feature but for many different commands as long as it allows implicit coercions. So when I want an AppleEvent descriptor as fileTypeUrl the AE framework will try to coerce the given argument if it’s of class string containing a POSIX or a HFS path. So you’re maybe glad to hear that it’s not only open for access that supports POSIX paths but a lot of more commands like deprecated info for and deprecated list folder
It is good to still learn something new, especially how file reference can be interpreted.
@ DJ Bazzie Wazzie: Thanks for the info, It is also nice to have learned that the correct way of trying to closing a file is to use its full path. Kudos to Stefan for bringing that onto the table. (It covers most cases, and is probably most convenient when you edit the code, espcecially when you are in an editor, that doesn’t take care of leaked file handles, or reference numbers. I see an advantage of writing code, so others can play with it, without being shot in the back, by suddenly having a file they can’t open.
By the way: I can’t see that list folder is deprecated.
‘close access’ + file specifier closes an unspecified access to the file, provided that the access is owned by the application running the script. If the application has several accesses open to the file, ‘close access’ + file specifier will close one of them, but you can’t know which.
‘open for access’ without write permission will only ever error if the path to the file’s incorrectly specified. In this case, using ‘close access’ ” whether with the incorrect file specifier or with the non-existent ‘open for access’ number ” is a waste of time.
‘open for access with write permission’ will only ever error if the path’s incorrectly specified as above or if the file’s already open with write permission. If some other application owns the write permission access, the script won’t be able to close it, so again using ‘close access’ is a waste of time. If the write permission access belongs to the script and is left over from a previous run, ‘close access’ + file specifier may close it, but it depends on point 1 above.
My own view is that it would be better to catch ‘open for access’ errors separately so that their causes can be investigated and fixed. If they’re the script’s fault, it would be better to fix the code causing them than blindly to close accesses. Something like the following, although I don’t usually bother with the first ‘try’ block myself:
try
set fileDescriptor to (open for access file aFilePath with write permission)
on error errMsg
display dialog errMsg buttons "Stop" default button 1 cancel button 1
end try
try
write stuff to fileDescriptor
-- do other stuff
on error errMsg
display dialog errMsg buttons "Stop" default button 1
end try
close access fileDescriptor
use framework "Foundation"
(current application's NSFileManager's defaultManager()'s contentsOfDirectoryAtPath:posixPath |error|:(missing value)) as list
@Nigel: If an error occurs while writing and the script hangs (read: write command doesn’t have a timeout) or unexpectedly quits, the second run your example code won’t be able to close the file properly because in your example you only close the file by it’s descriptor. I understand the problem of closing an file with read access opened by another application, but that is solved with an extra try around the closing in Stefan’s post.
How awkward, now I saw it clearly, I actually did, believe it or not, look it up in the Scripting Additions dictionary.
@Nigel, it of course depends on who it is sitting there, having problems with a file handler one can’t close. Say if one that hasn’t experienced this problem before, sits there, then it is better to close the file reference all together, so that the person in question can move on, without the befuddlement. And thanks for the writeup.
Other thing is file reference of file system, and other thing - file descriptor (of current application, many users name its variable fileRef, but its correct name is fileDescriptor for example).
This should close your opened descriptor (that is, to force the current application to forgot the file descriptor)
close access fileDescriptor
– close stored in the script file descriptor
If in advance, when opening a file for access, you did not save this descriptor to the script variable (fileDescriptor), then this means: your script has completely lost control over the file descriptor. In this case, you will have to restart the application for it to close all file descriptors.