Is there a bug in Leopard file writing?

G’day.

The following script, which I posted some time ago, no longer works under Leopard.

When I deliberately cancelled the dialog box in the second version of the script, and left the file open, I couldn’t close the ‘write’ being open, in this line.



close access TheFileName2


If I enclosed the file closing line in a try statement, the script declared that the file was still open


       try
	close access TheFileName2
	try
	
	

Anybody else having problems?

FIRST example (used to work under Tiger)


-- Timer

-- Not bloody copyright
-- Just fooling around.
-- Some examples of how time strings can be manipulated,
-- cause I found examples hard to find.
-- by Santa



my Timer()
my displayInfo()

on Timer()
	copy (current date) - (time to GMT) to tempDate -- For universal time
	copy tempDate to KeepTheTime
	
	-- For an invisible file, put a full stop in front of the name ie ".Timer"
	set t to my ReadTheTime("Timer", KeepTheTime)
	display dialog "elapsed : " & my setTheDaysHoursMinutesSeconds(KeepTheTime - t) buttons {"OK", "See elapsed time", "Reset Timer"}
	set temp to button returned of the result
	if temp = "Reset Timer" then
		copy (current date) - (time to GMT) to tempDate -- For universal time
		my SaveTheTime("Timer", tempDate)
		my Timer()
	else
		if temp = "See elapsed time" then my Timer()
	end if
end Timer

on displayInfo()
	copy (current date) - (time to GMT) to tempDate -- For universal time
	copy tempDate to KeepTheTime
	set time of tempDate to 0
	set dayelapsedtime to KeepTheTime - tempDate
	set day of tempDate to 1
	set monthelapsedtime to KeepTheTime - tempDate
	set month of tempDate to 1
	set yearlyelapsedtime to KeepTheTime - tempDate
	
	display dialog "Universal time" & return & return & ¬
		"Since midnight, " & dayelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(dayelapsedtime) & return & return & ¬
		"Since 12.00 am on the first of the month, " & monthelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(monthelapsedtime) & return & return & ¬
		"Since 12.00 am January 1, " & yearlyelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(yearlyelapsedtime) buttons {"OK", "Refresh information"}
	if button returned of the result = "Refresh information" then my displayInfo()
	
end displayInfo

on ReadTheTime(Filename, KeepTheTime)
	tell application "Finder"
		set TheFileName to (path to desktop folder as string) & Filename
		try
			set theSavedTime to (read file (TheFileName) as date)
			return theSavedTime
		on error
			my SaveTheTime(Filename, KeepTheTime)
			return KeepTheTime
		end try
	end tell
end ReadTheTime

on SaveTheTime(Filename, KeepTheTime)
	tell application "Finder"
		set TheFileName to (path to desktop folder as string) & Filename
	end tell
	try
		set fRef to (open for access file TheFileName with write permission)
	end try
	set eof fRef to 0
	--try
	display dialog TheFileName & KeepTheTime
	write KeepTheTime to fRef
	--end try
	close access fRef
end SaveTheTime

on setTheDaysHoursMinutesSeconds(theSeconds)
	
	set TheTotalDays to theSeconds div days
	set TheTotalHours to (theSeconds - (TheTotalDays * days)) div hours
	set thetotalminutes to (theSeconds - ((TheTotalDays * days) + (TheTotalHours * hours))) div minutes
	set theTotalSeconds to theSeconds - ((TheTotalDays * days) + (TheTotalHours * hours) + (thetotalminutes * minutes))
	set the AnswerString to ""
	if TheTotalDays > 0 then set the AnswerString to the AnswerString & TheTotalDays & " Days "
	if TheTotalHours > 0 then set the AnswerString to the AnswerString & TheTotalHours & " Hours "
	if thetotalminutes > 0 then set the AnswerString to the AnswerString & thetotalminutes & " Minutes "
	set the AnswerString to the AnswerString & theTotalSeconds & " Seconds."
	return the AnswerString
	
end setTheDaysHoursMinutesSeconds


SECOND example



-- Timer

-- Not bloody copyright
-- Just fooling around.
-- Some examples of how time strings can be manipulated,
-- cause I found examples hard to find.
-- by Santa


global TimerFile
set TimerFile to "Time3"

my Timer()
my displayInfo()

on Timer()
	copy (current date) - (time to GMT) to tempDate -- For universal time
	copy tempDate to KeepTheTime
	
	-- For an invisible file, put a full stop in front of the name ie ".Timer"
	set t to my ReadTheTime(TimerFile, KeepTheTime)
	display dialog "elapsed : " & my setTheDaysHoursMinutesSeconds(KeepTheTime - t) buttons {"OK", "See elapsed time", "Reset Timer"}
	set temp to button returned of the result
	if temp = "Reset Timer" then
		copy (current date) - (time to GMT) to tempDate -- For universal time
		my SaveTheTime(TimerFile, tempDate)
		my Timer()
	else
		if temp = "See elapsed time" then my Timer()
	end if
end Timer

on displayInfo()
	copy (current date) - (time to GMT) to tempDate -- For universal time
	copy tempDate to KeepTheTime
	set time of tempDate to 0
	set dayelapsedtime to KeepTheTime - tempDate
	set day of tempDate to 1
	set monthelapsedtime to KeepTheTime - tempDate
	set month of tempDate to 1
	set yearlyelapsedtime to KeepTheTime - tempDate
	
	display dialog "Universal time" & return & return & ¬
		"Since midnight, " & dayelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(dayelapsedtime) & return & return & ¬
		"Since 12.00 am on the first of the month, " & monthelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(monthelapsedtime) & return & return & ¬
		"Since 12.00 am January 1, " & yearlyelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(yearlyelapsedtime) buttons {"OK", "Refresh information"}
	if button returned of the result = "Refresh information" then my displayInfo()
	
end displayInfo

on ReadTheTime(Filename, KeepTheTime)
	tell application "Finder"
		set TheFileName to (path to desktop folder as string) & Filename
		try
			set theSavedTime to (read file (TheFileName) as date)
			return theSavedTime
		on error
			my SaveTheTime(Filename, KeepTheTime)
			return KeepTheTime
		end try
	end tell
end ReadTheTime

on SaveTheTime(Filename, KeepTheTime)
	set TheFileName to ((path to desktop as string) & Filename)
	set TheFileName2 to alias ((path to desktop as string) & Filename)
	close access TheFileName2
	set fRef to (open for access file TheFileName with write permission)
	
	set eof fRef to 0
	display dialog KeepTheTime as string
	write KeepTheTime to fRef
	try
		close access fRef
	end try
end SaveTheTime

on setTheDaysHoursMinutesSeconds(theSeconds)
	
	set TheTotalDays to theSeconds div days
	set TheTotalHours to (theSeconds - (TheTotalDays * days)) div hours
	set thetotalminutes to (theSeconds - ((TheTotalDays * days) + (TheTotalHours * hours))) div minutes
	set theTotalSeconds to theSeconds - ((TheTotalDays * days) + (TheTotalHours * hours) + (thetotalminutes * minutes))
	set the AnswerString to ""
	if TheTotalDays > 0 then set the AnswerString to the AnswerString & TheTotalDays & " Days "
	if TheTotalHours > 0 then set the AnswerString to the AnswerString & TheTotalHours & " Hours "
	if thetotalminutes > 0 then set the AnswerString to the AnswerString & thetotalminutes & " Minutes "
	set the AnswerString to the AnswerString & theTotalSeconds & " Seconds."
	return the AnswerString
	
end setTheDaysHoursMinutesSeconds


Which dialog? I don’t see close access TheFileName2 in either of your scripts.

G’day Bruce

In the second posted version, a dialog box comes up before writing to the file. If you Cancel and leave the file open, it can’t be closed.

The line

close access TheFileName2

only results then in the statement that the file in closed all ready, when in fact it’s not.

Enclosing the above line in try statements then results in being told that the file is already open.

Something screwy is going on, because the first script no longer writes to the file correctly.

Regards

Santa

Hi Santa,

the first script works fine in Leopard on my machine (G5 Dual)

The second one throws an error in this line


set TheFileName2 to alias ((path to desktop as string) & Filename)

because there is no file while running the script the first time

G’day once again Stefan.

The first script partly works on my Intel, but the timer keeps returning a value of 0.0 seconds, until I reset the time, then it returns all sorts of weird, negative times.

I tracked it down to the fact that the script doesn’t seem to be writing the time to the file correctly.

From that observation, I found that the script wasn’t writing to a text file at all correctly.

I’ve re-booted, and still the same problem.

If I run the first following script, which doesn’t close the file, the line that should close the file in the second script fails to ‘see’ the file as open.

Another thing, the newly created text files on my desktop don’t show up unless I quit and restart the finder.

Regards

Santa

First Script


copy (current date) - (time to GMT) to tempDate -- For universal time
copy tempDate to KeepTheTime

set Filename to "test4"
set TheFileName to (path to desktop as string) & Filename
set fRef to (open for access file TheFileName with write permission)
tell application "Finder"
	if (exists file TheFileName) then
		set TheFileName2 to ((path to desktop) & Filename) as string
		close access file TheFileName2
	end if
end tell
set eof fRef to 0
write KeepTheTime to fRef

Second Script


copy (current date) - (time to GMT) to tempDate -- For universal time
copy tempDate to KeepTheTime

set Filename to "test4"
set TheFileName to (path to desktop as string) & Filename
tell application "Finder"
	if (exists file TheFileName) then
		set TheFileName2 to ((path to desktop) & Filename) as string
		close access file TheFileName2
	end if
end tell
set eof fRef to 0
write KeepTheTime to fRef

Why not the “usual” order, the state of a file opened for access could be not stable

copy (current date) - (time to GMT) to tempDate -- For universal time
copy tempDate to KeepTheTime

set Filename to "test4"
set TheFileName to (path to desktop as string) & Filename
tell application "Finder"
	if (exists file TheFileName) then
		set TheFileName2 to ((path to desktop) & Filename) as string
		try
			close access file TheFileName2
		end try
	end if
end tell
set fRef to (open for access file TheFileName with write permission)
set eof fRef to 0
write KeepTheTime to fRef
close access fRef

Thanks Stefan, but when I run your script I get a ‘file is already open’ failure in the line…

set fRef to (open for access file TheFileName with write permission)

My problem is once the files open for write access, I can’t close it.

Regards

Santa

Me again.

From my tests, I suspect that the file is created, written too, and closed just fine, but on subsequent writes, it refuses to close, and the script keeps bombing cause it finds the file permanently open.

Might be a bug just with Intels and Leopard perhaps?

Santa

then you have a mess with your currently opened files.

The scripter has to take care that all opened files will be closed reliably before the script has finished :wink:

I believe that bit about closing files, but surely it’s possible to close the file with a correctly crafted script?

This first showed up because of a script error, where a file was left open. The only way I can close it is to log back in.

There must be a better way surely?

Santa

That’s what error handling is for.

Thanks Bruce, pearls of wisdom always welcome :confused:

I found the bug. The following writes the current date, which seems to vary each time, but an immediate read from the file ALWAYS returns 1 January 1904 12.00.00 am.

I doesn’t matter if I use…

write KeepTheTime as date to fRef

OR

write KeepTheTime to fRef

Could someone (anyone?) with Leopard on an Intel iMac try this out for me please?

Regards

Santa



-- Timer

-- Not bloody copyright
-- Just fooling around.
-- Some examples of how time strings can be manipulated,
-- cause I found examples hard to find.
-- by Santa


global TimeFile
set TimeFile to "Timer2"

my Timer()
my displayInfo()

on Timer()
	copy (current date) - (time to GMT) to tempDate -- For universal time
	copy tempDate to KeepTheTime
	
	-- For an invisible file, put a full stop in front of the name ie ".Timer"
	set t to my ReadTheTime(TimeFile, KeepTheTime)
	display dialog "elapsed : " & my setTheDaysHoursMinutesSeconds(KeepTheTime - t) buttons {"OK", "See elapsed time", "Reset Timer"}
	set temp to button returned of the result
	if temp = "Reset Timer" then
		copy (current date) - (time to GMT) to tempDate -- For universal time
		my SaveTheTime(TimeFile, tempDate)
		my Timer()
	else
		if temp = "See elapsed time" then my Timer()
	end if
end Timer

on displayInfo()
	copy (current date) - (time to GMT) to tempDate -- For universal time
	copy tempDate to KeepTheTime
	set time of tempDate to 0
	set dayelapsedtime to KeepTheTime - tempDate
	set day of tempDate to 1
	set monthelapsedtime to KeepTheTime - tempDate
	set month of tempDate to 1
	set yearlyelapsedtime to KeepTheTime - tempDate
	
	display dialog "Universal time" & return & return & ¬
		"Since midnight, " & dayelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(dayelapsedtime) & return & return & ¬
		"Since 12.00 am on the first of the month, " & monthelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(monthelapsedtime) & return & return & ¬
		"Since 12.00 am January 1, " & yearlyelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(yearlyelapsedtime) buttons {"OK", "Refresh information"}
	if button returned of the result = "Refresh information" then my displayInfo()
	
end displayInfo

on ReadTheTime(Filename, KeepTheTime)
	tell application "Finder"
		set TheFileName to (path to desktop folder as string) & Filename
		try
			set theSavedTime to (read file (TheFileName) as date)
			return theSavedTime
		on error
			my SaveTheTime(Filename, KeepTheTime)
			return KeepTheTime
		end try
	end tell
end ReadTheTime

on SaveTheTime(Filename, KeepTheTime)
	set TheFileName to ((path to desktop) & Filename) as string
	try
		set fRef to (open for access file TheFileName with write permission)
	on error
		try
			close access TheFileName
		end try
	end try
	try
		set eof fRef to 0
		display dialog KeepTheTime as string
		write KeepTheTime as date to fRef
		close access fRef
		delay 2
		set theSavedTime to (read file (TheFileName) as date)
		display dialog theSavedTime as string
	on error
		try
			close access fRef
		end try
	end try
end SaveTheTime

on setTheDaysHoursMinutesSeconds(theSeconds)
	
	set TheTotalDays to theSeconds div days
	set TheTotalHours to (theSeconds - (TheTotalDays * days)) div hours
	set thetotalminutes to (theSeconds - ((TheTotalDays * days) + (TheTotalHours * hours))) div minutes
	set theTotalSeconds to theSeconds - ((TheTotalDays * days) + (TheTotalHours * hours) + (thetotalminutes * minutes))
	set the AnswerString to ""
	if TheTotalDays > 0 then set the AnswerString to the AnswerString & TheTotalDays & " Days "
	if TheTotalHours > 0 then set the AnswerString to the AnswerString & TheTotalHours & " Hours "
	if thetotalminutes > 0 then set the AnswerString to the AnswerString & thetotalminutes & " Minutes "
	set the AnswerString to the AnswerString & theTotalSeconds & " Seconds."
	return the AnswerString
	
end setTheDaysHoursMinutesSeconds


The problem in your test scripts, at least, seems to be that you’re telling the application running the script (eg. Script Editor) to open an access to the file, but telling the Finder to close it. Since the Finder doesn’t own the access, it reports that the file’s not open.

I don’t know exactly what the problem is with with your main scripts, but you could start by getting rid of the Finder ‘tell’ blocks round the ‘path to’ and File Read/Write commands. And of course, putting the ‘try’ blocks in the right places to ensure that the file’s closed in the event of a script error. :wink:

It’s normally enough just to quit and reopen the application that opened the access(es). If that application’s the Finder or System Events, you might find logging out and back necessary.

By the way, with Tiger at least, there appears to be a bug in the Read/Write Commands that causes Intel machines to read dates incorrectly from file. I don’t know if that’s also the case in Leopard. (Edit: I see from your latest post that it is!)

G’day Nigel

Thanks for that.

Unfortunately I’ve got a very long script that a company uses for mail handling, and it uses time based files for error reporting.

They’re wanting to buy a new iMac to exclusively handle the mail, so I will have to put them off until Apple fix this problem.

Where can I report a bug to Apple (I know they’re probably aware of it, but I’d like to add my voice to those calling for a fix.)

Regards

Santa

Model: intel Core 2 Duo iMac
AppleScript: 2.1.1
Browser: Safari 3.0.4
Operating System: Mac OS X (10.5)

BTW, does anyone know if it’s possible, in some way, to read the date as a simple variable, then transpose that variable into a date?

Thanks

Santa

The following fails on the set theSavedTime to (theSavedTime as date) line…



on ReadTheTime(Filename, KeepTheTime)
	tell application "Finder"
		set TheFileName to (path to desktop folder as string) & Filename
		try
			set theSavedTime to (read file (TheFileName))
			say "here 1"
			set theSavedTime to (theSavedTime as date)
			say "here 2"
			return theSavedTime
		on error
			my SaveTheTime(Filename, KeepTheTime)
			return KeepTheTime
		end try
	end tell
end ReadTheTime

Model: intel Core 2 Duo iMac
AppleScript: 2.1.1
Browser: Safari 3.0.4
Operating System: Mac OS X (10.5)

You have to go through the rigmarole of registering as a developer if you want the “privilege” of reporting a bug. :confused:

Uh? :confused:

Would it work for you to save and read the date as «class isot» data?

set testFilePath to ((path to desktop as text) & "Date test.dat")

set d to (current date) as «class isot»
set fRef to (open for access file testFilePath with write permission)
try
	set eof fRef to 0
	write d to fRef
end try
close access fRef

set theDate to (read file testFilePath as «class isot») as date

Nigel, you deserve a medal, that worked fine, thank you.

Regards

Santa

Model: intel Core 2 Duo iMac
AppleScript: 2.1.1
Browser: Safari 3.0.4
Operating System: Mac OS X (10.5)

For posterity, here’s the script with Nigels fixes.



-- Timer

-- Not bloody copyright
-- Just fooling around.
-- Some examples of how time strings can be manipulated,
-- cause I found examples hard to find.
-- by Santa

my Timer()
my displayInfo()

on Timer()
	copy (current date) - (time to GMT) to tempDate
	-- For universal time
	copy tempDate to KeepTheTime
	
	-- For an invisible file, put a full stop in front of the name ie ".Timer"
	set t to my ReadTheTime("Timer", KeepTheTime)
	display dialog "elapsed : " & my setTheDaysHoursMinutesSeconds(KeepTheTime - t) buttons {"OK", "See elapsed time", "Reset Timer"}
	set temp to button returned of the result
	if temp = "Reset Timer" then
		copy (current date) - (time to GMT) to tempDate -- For universal time
		my SaveTheTime("Timer", tempDate)
		my Timer()
	else
		if temp = "See elapsed time" then my Timer()
	end if
end Timer

on displayInfo()
	copy (current date) - (time to GMT) to tempDate -- For universal time
	copy tempDate to KeepTheTime
	set time of tempDate to 0
	set dayelapsedtime to KeepTheTime - tempDate
	set day of tempDate to 1
	set monthelapsedtime to KeepTheTime - tempDate
	set month of tempDate to 1
	set yearlyelapsedtime to KeepTheTime - tempDate
	
	display dialog "Universal time" & return & return & ¬
		"Since midnight, " & dayelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(dayelapsedtime) & return & return & ¬
		"Since 12.00 am on the first of the month, " & monthelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(monthelapsedtime) & return & return & ¬
		"Since 12.00 am January 1, " & yearlyelapsedtime & " seconds have elapsed." & return & my setTheDaysHoursMinutesSeconds(yearlyelapsedtime) buttons {"OK", "Refresh information"}
	if button returned of the result = "Refresh information" then my displayInfo()
	
end displayInfo

on ReadTheTime(Filename, KeepTheTime)
	tell application "Finder"
		set TheFileName to (path to desktop folder as string) & Filename
		try
			set theSavedTime to (read file TheFileName as «class isot») as date
			return theSavedTime
		on error
			my SaveTheTime(Filename, KeepTheTime)
			return KeepTheTime
		end try
	end tell
end ReadTheTime

on SaveTheTime(Filename, KeepTheTime)
	tell application "Finder"
		set TheFileName to (path to desktop folder as string) & Filename
	end tell
	set fRef to (open for access file TheFileName with write permission)
	set eof fRef to 0
	try
		set KeepTheTime to KeepTheTime as «class isot»
		write KeepTheTime to fRef
	end try
	close access fRef
end SaveTheTime

on setTheDaysHoursMinutesSeconds(theSeconds)
	set TheTotalDays to theSeconds div days
	set TheTotalHours to (theSeconds - (TheTotalDays * days)) div hours
	set thetotalminutes to (theSeconds - ((TheTotalDays * days) + (TheTotalHours * hours))) div minutes
	set theTotalSeconds to theSeconds - ((TheTotalDays * days) + (TheTotalHours * hours) + (thetotalminutes * minutes))
	set the AnswerString to ""
	if TheTotalDays > 0 then set the AnswerString to the AnswerString & TheTotalDays & " Days "
	if TheTotalHours > 0 then set the AnswerString to the AnswerString & TheTotalHours & " Hours "
	if thetotalminutes > 0 then set the AnswerString to the AnswerString & thetotalminutes & " Minutes "
	set the AnswerString to the AnswerString & theTotalSeconds & " Seconds."
	return the AnswerString
end setTheDaysHoursMinutesSeconds


Model: intel Core 2 Duo iMac
AppleScript: 2.1.1
Browser: Safari 3.0.4
Operating System: Mac OS X (10.5)

Good! It works here too on both my PPC machines. :slight_smile:

May I suggest the following revamp of the Read/Write handlers for improved safety and efficiency? (Put the ‘try’ block round everything that happens while the file’s open for access. Dispense with the Finder.)

on ReadTheTime(Filename, KeepTheTime)
	set TheFileName to (path to desktop as text) & Filename
	try
		set theSavedTime to (read file TheFileName as «class isot») as date
		return theSavedTime
	on error
		my SaveTheTime(Filename, KeepTheTime)
		return KeepTheTime
	end try
end ReadTheTime

on SaveTheTime(Filename, KeepTheTime)
	set KeepTheTime to KeepTheTime as «class isot»
	
	set TheFileName to (path to desktop as text) & Filename
	set fRef to (open for access file TheFileName with write permission)
	try
		set eof fRef to 0
		write KeepTheTime to fRef
	end try
	close access fRef
end SaveTheTime

Also, by use of ‘mod’, which divides one number by another and returns just the remainder, the days/hours/minutes/seconds calculations could be reduced to:

set TheTotalDays to theSeconds div days
set TheTotalHours to theSeconds mod days div hours
set thetotalminutes to theSeconds mod hours div minutes
set theTotalSeconds to theSeconds mod minutes