Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Close an Open File, Not a Table 1

Status
Not open for further replies.

stanlyn

Programmer
Sep 3, 2003
945
US
Hi,

Assume that I opened a file with =FOPEN('d:\test.jpg',0)
Notice that I did not assign a variable to get the file's handle.

What commands could I use to close the file without knowing the handle?

Is there any commands where I can pass the filename in and close it?

I know the file is open by vfp as Win8 reports it as in use by vfp9 when I try to delete it at the OS level, and I'm looking for a way to close it, release it, unlock it from within vfp. If I close and restart vfp, the file can be deleted.

I've googled all over and cannot find any resource that shows how to close it, and many, many ways to test if it is open, but no way to close it if it's open.

Is there way of getting the handle to the open file?

How big is an average size handle, more than 2 digits?

Would something like this work?

x=1
do while x < 100
fclose(x) &&spinning through numbers 1-99
x=x+1
endo

What effects should I see with buffered vs unbuffered mode options for the fopen() function? Where is that discussed in detail?

Thanks,
Stanley
 
The question is irrelevant, you should ALWAYS store the file handle in a variable or a property. Unless you want to take risks.
 
I assume you don't talk of a file you really opened with FOPEN, because the solution then oviously is using the file handle you get.

You can't do much harm closing random handles, as the OS will only close files with handles your process owns, but CLOSE ALL is the easiest way to close all files, with the downside to close all. But you have the same problem with closing random handles, you might close files you need open. But you can answer that yourself, what's hindering you from simply trying it out?

I've experiences files kept open in VFP , especially COVERAGE files or ALTERNATE. Any file you open, also via USE or OPEN DATABASE will have a handle from the OS. I haven't tried, but you might not get those closed, if VFP itself keeps track of file handles used by fopen, then you won't get tables, databases, coverage logs or alternate output files closed this way but by closing VFP or doing CLOSE ALL/CLEAR ALL.

In regard to CLEAR ALL we had a lengthy discussion and in the end it pays to have an IDE reset prg with such things you can call to clear all such hanging references and open files, there's more to it, eg uncommited transaction, if TXNLEVEL()>0 you better rollback in such a reset case.

Bye, Olaf.

 
stanlyn,
Well, what's the aversion to just putting a variable in front of that =FOPEN() and then managing it the way FOPEN() intended? You have the solution but refuse to use it... that's odd.
Just keep hold of the handle in a variable, and when you're done release the handle and close the file... Why would you want another way to do this? There is no risk in close the handle given to you by FOPEN, as it will be unique.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
When all else fails, the magic bullet for closing files is:

Code:
QUIT

 
Scott,

>> Well, what's the aversion to just putting a variable in front of that =FOPEN() and then managing it the way FOPEN() intended?

If I use the fopen() function I would normally assign it to a variable. I know you've been following the thread "Run command works When IT wants to... thread184-1756028" where something was opening a file which caused the "cannot create file" error 1102 issues. The only way the code would work was by adding a forced wait state by adding inkey(1). The code worked, but remove the inkey function, and I'd immediately get the 1102 error. So, because I never used any file opening commands explicitly, I had no idea what the file handle was so I could use it to easily close it. Hence the question here. So to test, I intentionally opened a file without getting its handle and looked for way to close, (again, hence the question here). The only thing short of "quit" I found that worked and still left the table open was by creating this function:

Code:
function CloseFile
x=1
for x = 1 to 99
=fclose(x)
endfor
endfunc

I still don't know why I have to use this function to avoid the error as mentioned in the other thread.

What is fastest, a dowhile loop or a for loop?

Thanks, Stanley
 
Sorry, Stanley, but this is silly. Your function will close all open low-level files in all data sesssions. How do you know that there aren't any low-level files that need to stay open - such as those used within a generic function or class?

(Actually, it won't close all files - only the first 99, which might also be an issue.)

If your aim is to return the application to its initial state - a "clean slate" - then you would be better off doing CLOSE ALL.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Stanlyn,
I'm with Mike on this one... how do you know the file isn't open with a handle 101?
BUT I like to answer the question that's asked as well... Regarding the "Which is faster Do or For", my advise is if you have a loop of 99 iterations, it doesn't matter. No one will notice a couple milliseconds here or there.
Now, if you have a loop that is executed THOUSANDS of times (or more) then it matters.
One thing about loops I would say is, treat them as you would recursion... when your criteria is met, exit. Now in this case, you have no way to know, so you just execute on all of them. And there are times when that is also appropriate. For those, I would use a FOR loop, as apposed to a DO WHILE.
But the point here is to know WHY you are using one, and then pick appropriately. You're questions are great. Don't let others deter you asking them. We may from time to time point out that there is a "better way", and some will scold you, just ignore them. Most of the people here are very helpful. (Like Mike.)
-S

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
While I don't know a way to programmatically retrieve the number of the file handle, you can use DISPLAY STATUS or LIST STATUS and the full filename and the handle number will be among the first items listed, it will be under "User-opened files:". It also lists the Position|Read|Write attributes.
 
Hey Mike and Scott,

I totally agree with both of you, but until I find a way to know how to programmatically close the file that automatically closes whenever an inkey(1) is in place, I don't see any other option. I totally agree and don't want to start closing files blindly, which is exactly what I'm doing.

>> If your aim is to return the application to its initial state - a "clean slate" - then you would be better off doing CLOSE ALL.
A "close all" is also very disruptive. Would you want to do this 2 hours into a run when there is 4 more hours of records for it to do? I don't... I just need the file that was not explicitly opened to close, and it won't until I put in a inkey(1) or my CloseFile() function above. I've tried DoEvents with no success either. I've looked at adir(), but all methods I've been able to come up with is finding out it the file is open. I'm still waiting for a way to close it. Also, No success with an inkey() with a value less that (.07), while inkey(.10) works 95% of the time. I abandoned the inkey solution due to speed as having to add nearly a second to every record it processes would take far too long. My test bed of 400,000 records would take 11 hours just for the wait state...

The fox team left out fclose(&filename) or close(&filename) as in my case, I know the name of the file.

I'll be taking a close look at the DISPLAY STATUS or LIST STATUS commands to see what they yield. I'm sure those commands would help in troubleshoot and interactively close it if those numbers are shown. Those would not help me programmatically deal with it, would they?

So, how can I programmatically quickly close a file that I do know the path and name of, that was not explicitly opened by my code, thereby not having a handle.

Thanks,
Stanley


 
Unfortunately, if the path is too long, List Status shows an abbreviated path.
You can search only by file name, and find the handle of first occurrence.

Try filehandle function, based on brilliant dbMark's idea.

Code:
*********************************
* Demo prg
*********************************
LOCAL lcDesiredFile
IF !DIRECTORY("test_fopen")
	MD test_fopen
ENDIF
CD test_fopen
STRTOFILE("","1st.txt")
STRTOFILE("","2nd.txt")
STRTOFILE("","3rd.txt")
STRTOFILE("","4th.txt")

FOPEN("1st.txt")
FOPEN("2nd.txt")
FOPEN("3rd.txt")
FOPEN("4th.txt")

?filehandle("2nd.txt")
?FCLOSE(filehandle("2nd.txt"))
*********************************
* End Demo prg
*********************************


********************************************
* Function filehandle
* 	Return the handle for an open file
*	Parameter 
*		tcDesiredFile filename
*	Return values
*		-2 0 opened files
*		-1 file not found
*		>=0 first occurence's file handle
********************************************
FUNCTION filehandle
	LPARAMETERS tcDesiredFile
	tcDesiredFile = JUSTFNAME(m.tcDesiredFile)
	LOCAL lnLen,stfname,lnStatus,laStatus[1],lnHandle,lni,lnj
	lnLen = LEN(m.tcDesiredFile)
	stfname = FORCEEXT(SYS(2015),"txt")
	LIST STATUS NOCONSOLE TO (m.stfname)
	lnStatus = ALINES(laStatus,FILETOSTR(m.stfname),1+4)
	lnHandle = -2
	FOR lni = 1 TO m.lnStatus
		IF LEFT(laStatus[m.lni],18) == "User-opened files:"
			lnHandle = -1
			FOR lnj = m.lni + 1 TO m.lnStatus
				IF JUSTFNAME(LEFT(laStatus[m.lnj],38)) == UPPER(m.tcDesiredFile)
					lnHandle = VAL(STREXTRACT(laStatus[m.lnj],"Handle=",SPACE(1)))
					EXIT
				ENDIF
			NEXT
			EXIT
		ENDIF
	NEXT
	ERASE (m.stfname)
RETURN m.lnHandle

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
A "close all" is also very disruptive. Would you want to do this 2 hours into a run ....

Of course not. That's why I said "if you want to return the application to its initial state - a 'clean slate'". It's not something I would ever want to do. I was merely trying to guess what you were wanting to achieve.

The fox team left out fclose(&filename) or close(&filename)

That is precisly why file handles were invented.

I'll be taking a close look at the DISPLAY STATUS or LIST STATUS commands to see what they yield. I'm sure those commands would help in troubleshoot and interactively close it if those numbers are shown. Those would not help me programmatically deal with it, would they?

Well, you could use the TO FILE clause to pipe the output to a text file; then read that file into a variable via FILETOSTR(); then parse the variable to get the handle. For what it's worth, this is an extract from the resulting text file:

Code:
User-opened files:
  C:\TEST\JUNK.XLS  Handle=11 Pos=0 Read=Yes Write= No

So you could look for "User-opened files", then for the name of your file; then for the next occurrence of "Handle=", then for the subsequent integer. But it wouldn't be foolproof, and, as Vilhelm-Ion points out, it wouldn't work with long filenames or paths as these would be abbreviated.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Prehaps I'm confused, but if you have the code available, why not just put:

lnFileHandle =FOPEN('d:\test.jpg',0)

Find that line, put a variable in front of it???
Or is this a compiled .APP that you don't have source for???

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
>how to programmatically close the file that automatically closes whenever an inkey(1) is in place
Now you're making me curious about what you're doing at all.

If you open a file you know its handle and close it that way. Instead of trying to find code, that could work without the handle simply use it. If you open files via automation, eg Word or Excel, notice the autmation servers also have commands to close files.

Without knowing your problem in very detail it'll be hard to give you anything at hand. If you talk of files open by other processes a handle will not help you at all, you're only the owner of your (process) own file handles.

Bye, Olaf.
 
The fox team left out fclose(&filename) or close(&filename) as in my case, I know the name of the file.

You have answered your own question but you don't recognize it.

You know the name of the file AT THE TIME YOU OPEN IT. So you should remember the file handle AT THE TIME IT IS GIVEN TO YOU. That way you have it later, precisely at the time that you need the information that was given to you for the very purpose.

Code:
lnHandle = Fopen("file.whatever")

Later, you can

Code:
Fclose(lnHandle)

There's no special trickery. Any time you find yourself going to great lengths to accomplish something this simple you have simply ignored the easy, built-in mechanism for handling it.
 
So, how can I programmatically quickly close a file that I do know the path and name of, that was not explicitly opened by my code, thereby not having a handle.
That's a whole 'nuther critter. You have to glean the file handle from the server OS, then have the OS close it using calls to NetFileEnum, NetFileClose, etc.



-Dave Summers-
[cheers]
Even more Fox stuff at:
 
I regularly use Process Explorer by Mark Russinovich. Sysinternals was bought by Microsoft and his suite of tools is now on MS website. I can locate VFP in the process column under "explore.exe" and then in the lower pane I can list the various open files, threads, keys, etc.

That's on my computer. I have access to test on a web server, I can run Process Explorer from there and see VFP running (Process column) and/or the files (lower pane, Type = File). However, the File row for my opened file didn't reveal the Process ID (PID).

To get the PID I used the FIND menu to search for the file name opened with FOPEN. It will scan the system and report which process (PID) has that file open. I tested on my workstation and with that PID I went back to the lower pane and it listed that PID in 4 rows with 3 different sub-process numbers.

I don't know how helpful this information would be. The file handle used in VFP is not the computer or server's PID. But it shows there's a variety of ways to get environment data.
 
Stanlyn, you're talking about this?
Code:
lcOutFile = Strtofile(Filetostr('a.tmp') + lcKey1, 'z.tmp', 0)
INKEY(.03)
Copy File 'z.tmp' To (gcFileName)
So you say you want to close z.tmp? You can'tenforce it to close earlier than FilToStr() closes it, so what's really the point?

You're not alone an the system, you have 2,4,6,16 Cores? You hav X process and Y threads. Any file operation involves the OS, filesystem, drivers, ram, bus, etc.

Normally Copy File should only ever work when StrToFile is through, but if you always work with a.tmp and z.tmp, if this program runs on many clients and they all work on the same share or temp folder, then you you have to blame yourself about concurrency problems.

Simply use random file names, you can get via SYS(2015):

Code:
lcSourceFile = "org"+SYS(2015)+".tmp"
lcDestFile = "enc"+SYS(2015)+".tmp"

Now use lcSourceFile and lcDestFile instead of 'a.tmp' and 'z.tmp'.

Bye, Olaf.
 
Here is the code... If I remove the "Do CloseFile" call, I get the 1102 error on some (not all) records. The issue is with gcFileName being open just a little too long, and not the a.tmp or z.tmp files. This code has just finished processing 1,926,250 random sizes and file types without a single issue with the "Do CloseFile" function call. See the small screenshot displaying the time it takes encrypt and decrypt files to a harddrive and a ssd.

Also, many respondents here are somehow thinking I'm using a fopen() command in this code. I am not, nowhere! Checj for yourself, as the code is below... I know how to use fopen() and deal with file handles, but here I don't have a file handle that I can explicitly issue a fclose(nFileHandle) and be done with it.

So, to get past the 1102 error, so far i can insert a inkey(.1) in place of the "Do CloseFile", or use the "Do CloseFile". I have found NO other alternatives, and I've tried quite a few. Like I said earlier, I do not like to blindly close files as the "Do CloseFile" routine does. I see this as just another proof positive that the file is actually open.

Also note that skipping thru code without inkey() or the "Do CloseFile" stuff, the error does NOT occur. As the debugger is inducing a greater wait state that inkey(1), therfore gcFileName is auto-closing.

A special thanks to all that have responded, as I'm sure we will find a solution.
Stanley


Code:
	Do While !Eof('FileList')
		Y=Y+1
		r=r+1

		gcFileName = Alltrim(FileList.full_path)

		If File(gcFileName)
			Clear Resources

			sig = Right(Filetostr(gcFileName), 10)
			lcInfile = Filetostr(gcFileName)
			lnLen = Len(lcInfile)

			If lnLen <= 16777184
				If sig = lcKey1
					*?'File is currently encrypted'
					nStart = Seconds()
					lcOutFile = Strtofile(Left(lcInfile, Len(lcInfile)- 10), gcFileName, 0)
					Copy File (gcFileName) To 'a.tmp'
					llDecFailed = .F.
					Do FileDecrypt
					If llDecFailed = .F.
						Replace is_crypto With .F.
						lnLen = Len(Filetostr(gcFileName))

						If x < 3
							Replace dec1_size With lnLen
							Replace dhdd_sec With (Seconds() - nStart) && to harddrive
						Else
							Replace dec2_size With lnLen
							Replace dssd_sec With (Seconds() - nStart) && to ssd
						Endif
					Endif
				Else
					*?'Currently not encrypted'
					nStart = Seconds()
					llEncFailed = .F.

					Do FileEncrypt
					If llEncFailed = .F.
						Replace is_crypto With .T.
						lnLen = Len(Filetostr(gcFileName))

						If x < 3
							Replace enc1_size With lnLen
							Replace ehdd_sec With (Seconds() - nStart) && to harddrive
						Else
							Replace enc2_size With lnLen
							Replace essd_sec With (Seconds() - nStart) && to solidstatedrive
						Endif
					Endif
				Endif
			Else
				?Alltrim(gcFileName) + ' is larger than 16mb... ' + Alltrim(Str(((Len(Alltrim(lcInfile))/1024)/1024),6,3)) + ' MB'
				Delete
			Endif
		Else
			?Alltrim(gcFileName) + ' was NOT Found... '
		Endif

		Skip 1
		Loop
	Enddo

	tEnd = datetime()

	Do Case
		Case x = 1
			?ALLTRIM(str(tEnd-tTime,10)) + ' total seconds to Encrypt HDD Files'

		Case x = 2
			?ALLTRIM(str(tEnd-tTime,10)) + ' total seconds to DeCrypt HDD Files'

		Case x = 3
			?ALLTRIM(str(tEnd-tTime,10)) + ' total seconds to Encrypt SSD Files'

		Case x = 4
			?ALLTRIM(str(tEnd-tTime,10)) + ' total seconds to DeCrypt SSD Files'
	Endcase
Endfor

Release goCrypt

************************************************************************
Procedure FileEncrypt
	lnSuccess = goCrypt.CkEncryptFile(Alltrim(gcFileName), 'a.tmp')

	If (lnSuccess <> 1)
		=Messagebox(goCrypt.LastErrorText, 0, 'En-Cryption Error', 30000)
		llEncFailed = .T.
	Else
		llRetry = .T.
		lnTryCount = 0
		llReadOnly = .F.
		llResetReadOnly = .F.

		Do While llRetry = .T. .And. lnTryCount < 10
			llRetry = .F.
			lnTryCount = lnTryCount + 1

			=Adir(laFN, gcFileName)
			llReadOnly = 'R' $ laFN(1,5)

			If llReadOnly = .T.
				Store "Attrib -r " + '"' + (gcFileName) + '"' To cCommand
				Run /N2 &cCommand
				llRetry = .T.
				llResetReadOnly = .T.
			Else
				Do CloseFile
				Delete File (gcFileName)
				Exit
			Endif
		Enddo

		lcOutFile = Strtofile(Filetostr('a.tmp') + lcKey1, (gcFileName), 0)
		Do CloseFile

		If llResetReadOnly = .T.
			Store "Attrib +r " + '"' + (gcFileName) + '"' To cCommand
			Run /N2 &cCommand
		Endif

		Delete File 'a.tmp'
	Endif
Endproc


**************************************************************************************
Procedure FileDecrypt
	lnSuccess = goCrypt.CkDecryptFile(Alltrim(gcFileName), 'a.tmp')

	If (lnSuccess <> 1)
		=Messagebox(goCrypt.LastErrorText, 0, 'De-Cryption Error', 30000)
		llDecFailed = .T.
	Else
		llRetry = .T.
		lnTryCount = 0
		llReadOnly = .F.
		llResetReadOnly = .F.

		Do While llRetry = .T. .And. lnTryCount < 10
			=Adir(laFN, gcFileName)
			llReadOnly = 'R' $ laFN(1,5)

			If llReadOnly = .T.
				Store "Attrib -r " + '"' + (gcFileName) + '"' To cCommand
				Run /N2 &cCommand
				llRetry = .T.
				llResetReadOnly = .T.
			Else
				Do CloseFile
				Delete File (gcFileName)
				Exit
			Endif
		Enddo

		Store 'Copy File "a.tmp" To ' + '"' + (gcFileName) + '"' To zCommand
		&zCommand

		If llResetReadOnly = .T.
			Store "Attrib +r " + '"' + (gcFileName) + '"' To cCommand
			Run /N2 &cCommand
		Endif

		Delete File 'a.tmp'
	Endif
Endproc


***********************************************************************************
Procedure CloseFile
	z=1
	Do While z < 100
		Fclose(z)
		z=z+1
	Enddo

	Release z
Endproc
 
Olaf,
>> Simply use random file names, you can get via SYS(2015):
>> lcSourceFile = "org"+SYS(2015)+".tmp"
>> lcDestFile = "enc"+SYS(2015)+".tmp"
>> Now use lcSourceFile and lcDestFile instead of 'a.tmp' and 'z.tmp'.

The issue is not with the a.and z.tmp files. It is with gcFileName which is the same as allt(FileList.full_path). Only problem here is knowing its handle id.


>> Normally Copy File should only ever work when StrToFile is through, but if you always work with a.tmp and z.tmp
That is what I thought, but clearly is not the case here????

Oh, and here is the screenshot I forgit to add in the previous post...

Thanks,
Stanley
 
 http://files.engineering.com/getfile.aspx?folder=e076c0df-53ed-4a65-ae23-cea81df44fc1&file=Picture0001.png
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top