I have a script where all I want to do is write the current date to file in the HD/Library/Preferences folder. I can’t get past two stupid errors, though.
The script:
set userPrefs to (path to preferences from user domain) as string
set F to (userPrefs & "Example.txt")
set fRef to open for access file F with write permission
write (current date) to fRef
close access fRef
gets “File is already open” and the script:
set theDate to (current date)
close access (open for access file ((path to preferences folder as Unicode text) & "Example.txt"))
set F to ((path to preferences folder as Unicode text) & "Example.txt")
write theDate to F
close access F
set userPrefs to (path to preferences from user domain) as string
set F to (userPrefs & "Example.txt")
set _Date to (current date) as text
try
close access file F
end try
set fRef to open for access file F with write permission
write _Date to fRef
close access file F
Two notes:
The scripter must take care about the open/close status of the files, because you can’t reopen a file, which is already open.
You can’t write current date directly to a .txt file, because it’s of class date and you can only write text to a .txt file
The first script is probably failing because the file’s already open with write permission “ probably because the script stopped for an error on a previous run and didn’t close the access. If you save the script and quit Script Editor, that should close all Script Editor’s open accesses to the file. You can then launch Script Editor again and carry on. It’s a good idea to put everything you do while the file’s open in a ‘try’ block, so that the script can recover from any errors and close the access:
set userPrefs to (path to preferences as Unicode text)
set F to (userPrefs & "Example.txt")
set fRef to (open for access file F with write permission)
try
set eof fRef to 0
write (current date) to fRef
end try
close access fRef
The second script opens another access to the file “ this one without write permission “ and immediately closes it. However, the access with write permission will still be open if it was open before. (There can be several accesses open at a time to a file, only one of which can have write permission.) Either way you should still be able to write to the file. Your error seems to stem from the fact that you’re using a text path instead of a file reference to refer to the file. Since F has a text value, you should write to and close either ‘file F’ or ‘alias F’.
set theDate to (current date)
-- This opens a non-write access to the file and immediately closes it,
-- creating the file if it doesn't already exist.
close access (open for access file ((path to preferences as Unicode text) & "Example.txt"))
set F to ((path to desktop as Unicode text) & "Example.txt")
-- Unless there are any other accesses open, the line below will reopen the file
-- with write permission, write the date to it, and close the access.
-- If there are other accesses still open, what happens depends on which one is found first.
-- If the found access has write permission, it'll be used and it'll stay open.
-- If it doesn't have write permission, there'll be an error.
write theDate to file F
You can in fact write almost anything to a “.txt” file, but perhaps you shouldn’t because it’s misleading. Some other extension “ say “.dat” “ would be better.
When you want to read back your date object, you’ll need to read it ‘as date’.
set savedDate to (read file ((path to preferences as Unicode text) & "Example.dat") as date)
where currentDate is the current date in a variable and firstUsed is the date being read from Example.dat. I am writing to the file as a date and reading from it as a date, and when I check the file, I can see the date. However, when I use this code:
set firstUsed to (read file ((path to preferences as Unicode text) & "Example.dat") as date)
It always ends up being the date: Friday, January 1, 1904 12:00:00 AM.
try
set firstUsed to (read file ((path to preferences as Unicode text) & "Example.dat") as date)
set Purchase to display dialog "You are currently using a demo version of this application, would you like to purchase a license?" buttons {"Yes", "No"} default button 1
if button returned of Purchase is "Yes" then
tell application "Safari"
make new document with properties {URL:"http://www.google.com"}
end tell
else if button returned of Purchase is "No" then
-- do nothing
end if
on error
set userPrefs to (path to preferences from user domain) as string
set F to (userPrefs & "Example.dat")
set _Date to (current date) as date
try
close access file F
end try
set fRef to open for access file F with write permission
write _Date to fRef
close access file F
set firstUsed to (read file ((path to preferences as Unicode text) & "Example.dat") as date)
end try
set currentDate to (current date)
display dialog currentDate as string
display dialog firstUsed as string
if ((currentDate - 1) > firstUsed) then
display dialog "I will quit now!"
else
display dialog "Hey!"
end if
When you write an AppleScript date (only) to a file, the file should then have eight bytes. These represent a long integer whose value is the number of seconds since 1 January 1904 00:00:00. If that’s the date you’re getting back, it means that eight bytes of 0 are being read by your ‘read’ lines “ which suggests some problem with the file or with the number of accesses that are open to it. Your script works OK on my machine, but has a couple of vulnerabilities.
Here’s a slight rewrite that should allow it to work whatever the mess over accesses. It assumes that the date will be the only datum in the file. Scrap your existing “Example.dat” file first though before trying it.
try
-- Read the file specifically from the beginning, in case there's an access open
-- that's been used and whose file mark isn't pointing to the beginning anyway.
set firstUsed to (read file ((path to preferences as Unicode text) & "Example.dat") from 1 as date)
set Purchase to display dialog "You are currently using a demo version of this application, would you like to purchase a license?" buttons {"Yes", "No"} default button 1
if button returned of Purchase is "Yes" then
tell application "Safari"
make new document with properties {URL:"http://www.google.com"}
end tell
else if button returned of Purchase is "No" then
-- do nothing
end if
on error
set userPrefs to (path to preferences as Unicode text)
set F to (userPrefs & "Example.dat")
set _Date to (current date)
-- The current 'on error' block is only executed if the file doesn't exist,
-- so there's no point in trying to close any accesses to it.
(* try
close access file F
end try *)
-- Open an access with write permission.
set fRef to open for access file F with write permission
-- Use a 'try' block to catch any errors while the access is open.
try
-- Using this access, set the length of the file to 0, effectually emptying it and resetting the file mark to 1.
set eof fRef to 0
-- Write the date to the file, using this specific access.
write _Date to fRef
end try
-- Close this specific access.
close access fRef
-- Read the file specifically from the beginning, in case there's still an access open
-- that's been used and whose file mark isn't pointing to the beginning anyway.
set firstUsed to (read file ((path to preferences as Unicode text) & "Example.dat") from 1 as date)
end try
set currentDate to (current date)
display dialog currentDate as string
display dialog firstUsed as string
if ((currentDate - 1) > firstUsed) then
display dialog "I will quit now!"
else
display dialog "Hey!"
end if
‘(currentDate - 1)’ is of course one second before ‘currentDate’. I assume you’re using it for testing purposes.
Hmm. It works on both my machines and should do so.
I can get it to return the 1 January 1904 date by deliberately setting the ‘read’ lines to read from the wrong place in the file; so the only guesses I have at the moment about the cause(s) of your problem “ none of which seems very likely “ are:
You’re still working with an old version of the file.
You’re doing something else you’re not telling us about.
You have an Intel machine and there’s some hitherto undetected bug in the File Read/Write commands on Intel machines whereby dates are written to file using one convention and read back using another. If you do have an Intel machine, you could try giving the ‘write’ line an explicit ‘as date’ to see if that’s any improvement over the current implicit one, but I’ve no particular reason to think that it will be:
write _Date as date to fRef -- NB. No parentheses round '_Date as date'.
Otherwise, I don’t know what to suggest. If the above modification does happen to cure the problem, could you let us know? It’s useful information.
For what its worth, I am using an Intel machine, and that last suggestion didn’t work. Thats weird that it works on yours and not mine. Hopefully Ill figure this out. Thanks for all your time.
Something like that when I read it as text, but with a gap in front of it. If you read the file ‘as integer’ instead of ‘as date’, you should get a two-item list containing a zero followed by a negative number. (The eight bytes are returned as two four-byte integers.) I suspect that your Intel machine may be swapping these round when it writes the date to the file, so that the zero comes after the other number rather than before it. Is that the case?
Test script:
set filePath to (path to desktop as Unicode text) & "Test.dat"
set fRef to (open for access file filePath with write permission)
try
set eof fRef to 0
write (current date) as date to fRef
end try
close access fRef
read file filePath as integer
set filePath to (path to desktop as Unicode text) & "Test.dat"
set fRef to (open for access file filePath with write permission)
try
set theDate to (current date) as string
set eof fRef to 0
write theDate as string to fRef
end try
close access fRef
set filePath2 to read file filePath as string from 1
set theDate2 to filePath2 as string
That works for me!
thanks for all of your help, though!!
That looks right. But presumably, if you change the last line to ‘read file filePath as date’, you still get the 1904 date. If so, your machine’s not reading correctly ‘as date’.
Your coercion-to-string idea should be bullet-proof as regards reading and writing, and ‘date theDate2’ will usually give you an AppleScript date that can be used for the comparison in your original script. However, the string’s text is determined by the user’s own date format preferences, as set in System Preferences. If the user changes those preferences some time after the file’s written (unlikely, but both possible and legal), there’s a possibility that AppleScript won’t then be able to understand the string to turn it back to a date. (Also, a string date is the easiest data for an amateur to hack and alter to their own advantage “ which seems relevant to your script.)
Other things you might care to try are:
Read the stored date ‘as double integer’ and add the result to the 1904 base date:
set filePath to (path to desktop as Unicode text) & "Test.dat"
set fRef to (open for access file filePath with write permission)
try
set eof fRef to 0
write (current date) as date to fRef
end try
close access fRef
(«data isot313930342D30312D3031» as date) + (read file filePath as double integer)
-- The '«data isot.» as date' business is just a form of script text that gets
-- 1st January 1904 00:00:00 as an AppleScript date on anyone's machine.
Write and read a record containing the date:
set filePath to (path to desktop as Unicode text) & "Test.dat"
set fRef to (open for access file filePath with write permission)
try
set eof fRef to 0
write {aardvark:current date} to fRef
end try
close access fRef
(read file filePath as record)'s aardvark
Write and read a list containing the date:
set filePath to (path to desktop as Unicode text) & "Test.dat"
set fRef to (open for access file filePath with write permission)
try
set eof fRef to 0
write {current date} to fRef
end try
close access fRef
beginning of (read file filePath as list)
I’ve asked the Intel users on the AppleScript-Users mailing list to try out my test script (post #13 above, but reading ‘as date’). Everyone who’s replied gets the 1904 date back from it. Someone with both an Intel and a PPC confirms that the file contents are the same in both cases, but the Intel machine reads them back incorrectly.