Discussion:
Open file for exclusive access
(too old to reply)
char1iecha1k
2007-05-14 21:07:51 UTC
Permalink
Hi,

I would like to open a file for exclusive access for the duration of a
script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.

Thanks in advance
RichS
2007-05-15 08:09:02 UTC
Permalink
Is this for reading, writing or both
--
Richard Siddaway
Please note that all scripts are supplied "as is" and with no warranty
Blog: http://richardsiddaway.spaces.live.com/
PowerShell User Group: http://www.get-psuguk.org.uk
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of a
script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
char1iecha1k
2007-05-15 09:11:51 UTC
Permalink
Post by RichS
Is this for reading, writing or both
--
Richard Siddaway
Please note that all scripts are supplied "as is" and with no warranty
Blog:http://richardsiddaway.spaces.live.com/
PowerShell User Group:http://www.get-psuguk.org.uk
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of a
script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
I want to open file for reading, and when open disallow any other
process from opening that file. So far I have this

$test1=new-object System.IO.FileStream("test1.txt",
[System.IO.FileMode]::Open)

Now I need to know how to return the state of the file into a variable
so that my script can move on to the next unopen file ie

for each file in folder open file (if $file already open then return,
else process job)

hope that makes sense
Oisin Grehan
2007-05-15 12:54:22 UTC
Permalink
This post might be inappropriate. Click to display it.
char1iecha1k
2007-05-15 14:01:15 UTC
Permalink
Post by Oisin Grehan
Post by char1iecha1k
Post by RichS
Is this for reading, writing or both
--
Richard Siddaway
Please note that all scripts are supplied "as is" and with no warranty
Blog:http://richardsiddaway.spaces.live.com/
PowerShell User Group:http://www.get-psuguk.org.uk
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of a
script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
I want to open file for reading, and when open disallow any other
process from opening that file. So far I have this
$test1=new-object System.IO.FileStream("test1.txt",
[System.IO.FileMode]::Open)
Now I need to know how to return the state of the file into a variable
so that my script can move on to the next unopen file ie
for each file in folder open file (if $file already open then return,
else process job)
hope that makes sense- Hide quoted text -
- Show quoted text -
Do you have control of these other scripts? If so, why not use a
traditional ".lock" file - e.g. when you start up, create a file
called "mydatafile.lock," and delete it when you're finished. All
scripts should look for this while on start up, and quit if it already
exists.
Thats the way I do it at the moment. If the script errors for some
unkown reason then the lock file doesnt get removed.

If I open a file in a script as soon as the script ends (due to an
error or natural cause) the file will close.

I have got a bit further, but there are some peculiarities. Here is
the relevant bit of the script :

&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("file.lck",
[System.IO.FileMode]::Open)
}
write-host "success"

if the file isnt opened anywhere else then there will be no error in
the script block and the file is opened.
if the file is opened in another process then creating the new object
fails and and the trap handler exits the script.
as soon as the script finishes or exits the filestream is closed

this all works but if you run that piece of code in a test batch file
and keep running it then some times it displays an error and sometimes
not. here is a sample output below

1# gc test.ps1
&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("cmdc.lck",
[System.IO.FileMode]::Open)
}
write-host "success"
2# .\test.ps1
success
3# .\test.ps1
success
4# .\test.ps1
success
5# .\test.ps1
error
6# .\test.ps1
success
7# .\test.ps1
error
8# .\test.ps1
success
9# .\test.ps1
error
10# .\test.ps1
success
11# .\test.ps1
error
12# .\test.ps1
success
13# .\test.ps1
success
14# .\test.ps1
error
15# .\test.ps1
error
Marco Shaw
2007-05-15 14:19:35 UTC
Permalink
Post by char1iecha1k
Post by Oisin Grehan
Post by char1iecha1k
Post by RichS
Is this for reading, writing or both
--
Richard Siddaway
Please note that all scripts are supplied "as is" and with no warranty
Blog:http://richardsiddaway.spaces.live.com/
PowerShell User Group:http://www.get-psuguk.org.uk
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of a
script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
I want to open file for reading, and when open disallow any other
process from opening that file. So far I have this
$test1=new-object System.IO.FileStream("test1.txt",
[System.IO.FileMode]::Open)
Now I need to know how to return the state of the file into a variable
so that my script can move on to the next unopen file ie
for each file in folder open file (if $file already open then return,
else process job)
hope that makes sense- Hide quoted text -
- Show quoted text -
Do you have control of these other scripts? If so, why not use a
traditional ".lock" file - e.g. when you start up, create a file
called "mydatafile.lock," and delete it when you're finished. All
scripts should look for this while on start up, and quit if it already
exists.
Thats the way I do it at the moment. If the script errors for some
unkown reason then the lock file doesnt get removed.
If I open a file in a script as soon as the script ends (due to an
error or natural cause) the file will close.
I have got a bit further, but there are some peculiarities. Here is
&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("file.lck",
[System.IO.FileMode]::Open)
}
write-host "success"
if the file isnt opened anywhere else then there will be no error in
the script block and the file is opened.
if the file is opened in another process then creating the new object
fails and and the trap handler exits the script.
as soon as the script finishes or exits the filestream is closed
this all works but if you run that piece of code in a test batch file
and keep running it then some times it displays an error and sometimes
not. here is a sample output below
1# gc test.ps1
&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("cmdc.lck",
[System.IO.FileMode]::Open)
}
write-host "success"
2# .\test.ps1
success
3# .\test.ps1
success
4# .\test.ps1
success
5# .\test.ps1
error
6# .\test.ps1
success
7# .\test.ps1
error
8# .\test.ps1
success
9# .\test.ps1
error
10# .\test.ps1
success
11# .\test.ps1
error
12# .\test.ps1
success
13# .\test.ps1
success
14# .\test.ps1
error
15# .\test.ps1
error
Sounds like you need to set your PSH script to continue even if there's
a failure of any sorts so the lock gets created, then removed even if
any commands within it fail?

http://blogs.msdn.com/powershell/archive/2006/04/25/583241.aspx
char1iecha1k
2007-05-15 15:03:42 UTC
Permalink
Post by Marco Shaw
Post by char1iecha1k
Post by Oisin Grehan
Post by char1iecha1k
Post by RichS
Is this for reading, writing or both
--
Richard Siddaway
Please note that all scripts are supplied "as is" and with no warranty
Blog:http://richardsiddaway.spaces.live.com/
PowerShell User Group:http://www.get-psuguk.org.uk
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of a
script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
I want to open file for reading, and when open disallow any other
process from opening that file. So far I have this
$test1=new-object System.IO.FileStream("test1.txt",
[System.IO.FileMode]::Open)
Now I need to know how to return the state of the file into a variable
so that my script can move on to the next unopen file ie
for each file in folder open file (if $file already open then return,
else process job)
hope that makes sense- Hide quoted text -
- Show quoted text -
Do you have control of these other scripts? If so, why not use a
traditional ".lock" file - e.g. when you start up, create a file
called "mydatafile.lock," and delete it when you're finished. All
scripts should look for this while on start up, and quit if it already
exists.
Thats the way I do it at the moment. If the script errors for some
unkown reason then the lock file doesnt get removed.
If I open a file in a script as soon as the script ends (due to an
error or natural cause) the file will close.
I have got a bit further, but there are some peculiarities. Here is
&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("file.lck",
[System.IO.FileMode]::Open)
}
write-host "success"
if the file isnt opened anywhere else then there will be no error in
the script block and the file is opened.
if the file is opened in another process then creating the new object
fails and and the trap handler exits the script.
as soon as the script finishes or exits the filestream is closed
this all works but if you run that piece of code in a test batch file
and keep running it then some times it displays an error and sometimes
not. here is a sample output below
1# gc test.ps1
&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("cmdc.lck",
[System.IO.FileMode]::Open)
}
write-host "success"
2# .\test.ps1
success
3# .\test.ps1
success
4# .\test.ps1
success
5# .\test.ps1
error
6# .\test.ps1
success
7# .\test.ps1
error
8# .\test.ps1
success
9# .\test.ps1
error
10# .\test.ps1
success
11# .\test.ps1
error
12# .\test.ps1
success
13# .\test.ps1
success
14# .\test.ps1
error
15# .\test.ps1
error
Sounds like you need to set your PSH script to continue even if there's
a failure of any sorts so the lock gets created, then removed even if
any commands within it fail?
http://blogs.msdn.com/powershell/archive/2006/04/25/583241.aspx
I don't wont to continue if the file is already open. If the file is
not open then I want to open it.

If after that the script fails or finishes naturally then the I want
the filestream to close, which it does most of the time, but as shown
above sometimes it doesn't work properly. I have executed the script
manually (once every second) to produce the output above. Even when
leaving a good 5 seconds between executions it still sometimes errors.
This shouldn't happen, if it should then I need to know why and how to
avoid it
Keith Hill
2007-05-15 15:16:16 UTC
Permalink
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of a
script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
Perhaps you should try this FileStream constructor:

public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)

And set the share parameter to FileShare.None.

--
Keith
Joris van Lier
2007-05-15 15:33:20 UTC
Permalink
Post by Keith Hill
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of
a script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)
And set the share parameter to FileShare.None.
Good suggestion,

Is the FileShare.None option enough to lock the file or should one call $fileStream.Lock(0,$filestream.Length-1)?

And how about unlocking the file, will dereferencing the FileStream lift the lock, or is an explicit call to unlock required/recommended?
--
Joris van Lier
Please note that all scripts and opinions are supplied "as is" and with
no warranty Blog: http://whizzrd.spaces.live.com
Keith Hill [MVP]
2007-05-15 19:32:24 UTC
Permalink
If you use the FileShare parameter then the file will be locked to anyone
else until the file is closed (by disposing of the FileStream). The
Lock/Unlock methods allow you lock/unlock certain regions of a file where
that file allows write access to others.

--
Keith
Post by Keith Hill
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of
a script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)
And set the share parameter to FileShare.None.
Good suggestion,

Is the FileShare.None option enough to lock the file or should one call
$fileStream.Lock(0,$filestream.Length-1)?

And how about unlocking the file, will dereferencing the FileStream lift the
lock, or is an explicit call to unlock required/recommended?
--
Joris van Lier
Please note that all scripts and opinions are supplied "as is" and with
no warranty Blog: http://whizzrd.spaces.live.com
char1iecha1k
2007-05-15 21:49:46 UTC
Permalink
On 15 May, 20:32, "Keith Hill [MVP]"
Post by Keith Hill [MVP]
If you use the FileShare parameter then the file will be locked to anyone
else until the file is closed (by disposing of the FileStream). The
Lock/Unlock methods allow you lock/unlock certain regions of a file where
that file allows write access to others.
--
Keith
Post by Keith Hill
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of
a script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)
And set the share parameter to FileShare.None.
Good suggestion,
Is the FileShare.None option enough to lock the file or should one call
$fileStream.Lock(0,$filestream.Length-1)?
And how about unlocking the file, will dereferencing the FileStream lift the
lock, or is an explicit call to unlock required/recommended?
--
Joris van Lier
Please note that all scripts and opinions are supplied "as is" and with
no warranty Blog:http://whizzrd.spaces.live.com
OK tried this
char1iecha1k
2007-05-15 21:53:56 UTC
Permalink
On 15 May, 20:32, "Keith Hill [MVP]"
Post by Keith Hill [MVP]
If you use the FileShare parameter then the file will be locked to anyone
else until the file is closed (by disposing of the FileStream). The
Lock/Unlock methods allow you lock/unlock certain regions of a file where
that file allows write access to others.
--
Keith
Post by Keith Hill
Post by char1iecha1k
Hi,
I would like to open a file for exclusive access for the duration of
a script. If the script fails or finishes the lock must be released.
This is to prevent another user or process from accessing the same
data file. I have googled to no avail.
Thanks in advance
public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)
And set the share parameter to FileShare.None.
Good suggestion,
Is the FileShare.None option enough to lock the file or should one call
$fileStream.Lock(0,$filestream.Length-1)?
And how about unlocking the file, will dereferencing the FileStream lift the
lock, or is an explicit call to unlock required/recommended?
--
Joris van Lier
Please note that all scripts and opinions are supplied "as is" and with
no warranty Blog:http://whizzrd.spaces.live.com
ok this is what i get, it still randomly (as far as i can tell) fails

1# gc test.ps1
&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("cmdc.lck",
[System.IO.FileMode]::Open, [System.IO.FileAccess]::Read,
[system.Io.FileShare]::None)
}
write-host "success"
2# .\test.ps1
success
3# .\test.ps1
error
4# .\test.ps1
success
5# .\test.ps1
success
6# .\test.ps1
error
7# .\test.ps1
error
Keith Hill [MVP]
2007-05-15 22:46:58 UTC
Permalink
Post by char1iecha1k
ok this is what i get, it still randomly (as far as i can tell) fails
1# gc test.ps1
&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("cmdc.lck",
[System.IO.FileMode]::Open, [System.IO.FileAccess]::Read,
[system.Io.FileShare]::None)
}
write-host "success"
2# .\test.ps1
success
3# .\test.ps1
error
4# .\test.ps1
success
5# .\test.ps1
success
6# .\test.ps1
error
7# .\test.ps1
error
I think the "non-determinism" you are seeing are the resulting of the
garbage collector sporadically closing the "for you". If you want to avoid
this, then you should explicitly close the file when you are done with it.
I would modify the test like so:

&{
trap { write-host "error"; exit }
$script:test = new-object System.IO.FileStream("cmdc.lck",
[System.IO.FileMode]::Open, [System.IO.FileAccess]::Read,
[system.Io.FileShare]::None)
Start-Sleep -seconds 30
$script:test.dispose()
}

Now run your test in one PowerShell and then try to run the same script from
another console. The separate console should consistenly fail until the
first script execution times out and closes the file.

--
Keith
Keith Hill
2007-05-16 04:15:17 UTC
Permalink
Post by Keith Hill [MVP]
I think the "non-determinism" you are seeing are the resulting of the
garbage collector sporadically closing the "for you".
Doh! That should read:

I think the "non-determinism" you are seeing is the result of the
garbage collector sporadically collecting and closing the file "for you".

Since you don't close the file explicitly the file won't get closed until
the GC notices that the FileStream object that you created during the
previous script execution is no longer needed and finalizes it (which closes
the underlying file hanlde).

--
Keith
char1iecha1k
2007-05-18 13:52:02 UTC
Permalink
Post by Keith Hill
Post by Keith Hill [MVP]
I think the "non-determinism" you are seeing are the resulting of the
garbage collector sporadically closing the "for you".
I think the "non-determinism" you are seeing is the result of the
garbage collector sporadically collecting and closing the file "for you".
Since you don't close the file explicitly the file won't get closed until
the GC notices that the FileStream object that you created during the
previous script execution is no longer needed and finalizes it (which closes
the underlying file hanlde).
--
Keith
When the script runs it sometimes reports a locked file and sometimes
it doesnt, this is probably the "garbage collector" as you say,
however whilst that shell is still open the file remains locked to
other process. the only way to clear the lock is to end the shell.

an alternate method would be to use an trap handler to close the
stream on a file already open error. something like below. Does anyone
know what type of an exception this error is?
"
New-Object : Exception calling ".ctor" with "4" argument(s): "The
process cannot access the file 'C:\test.lck' because it is being used
by another process."
At C:\test.ps1:15 char:26
+ $script:test = new-object <<<< System.IO.FileStream("test.lck",
[System.IO.FileMode]::Open, [System.IO.FileAccess]::
Read, [system.Io.FileShare]::None)
"

then I could do something like this (i dont know wht the exception
type is?)

Trap [Exceptiontype] { Write-Host "file in use" -foregroundcolor red;
$Script:lck.close(); Exit }
$Script:lck = New-Object System.IO.FileStream("test.lck",
[System.IO.FileMode]::Open, [System.IO.FileAccess]::Read,
[system.Io.FileShare]::None)

then if the script errors before it finishes the trap handler will
close the stream
Keith Hill
2007-05-18 17:54:23 UTC
Permalink
Post by char1iecha1k
When the script runs it sometimes reports a locked file and sometimes
it doesnt, this is probably the "garbage collector" as you say,
however whilst that shell is still open the file remains locked to
other process. the only way to clear the lock is to end the shell.
...
Post by char1iecha1k
an alternate method would be to use an trap handler to close the
stream on a file already open error. something like below. Does anyone
know what type of an exception this error is?
"
then I could do something like this (i dont know wht the exception
type is?)
You don't have to specify an exception type, you could just trap all errors.
Post by char1iecha1k
Trap [Exceptiontype] { Write-Host "file in use" -foregroundcolor red;
$Script:lck.close(); Exit }
$Script:lck = New-Object System.IO.FileStream("test.lck",
[System.IO.FileMode]::Open, [System.IO.FileAccess]::Read,
[system.Io.FileShare]::None)
then if the script errors before it finishes the trap handler will
close the stream
Try this variant and see what you think:

param([switch]$Wait)

function Cleanup {
if ($script:test) {
$script:test.dispose()
$script:test = $null
}
}

trap { write-host "Error: $_"; Cleanup; exit }

$fileOpenArgs = "cmdc.lck", [IO.FileMode]::OpenOrCreate, [IO.FileAccess]::Read, [IO.FileShare]::None

if ($Wait) {
$secs = 10
do {
trap {
write-warning "Lock file in use. Waiting $secs seconds"
write-debug "$_"
start-sleep $secs
continue
}

$script:test = new-object System.IO.FileStream $fileOpenArgs
}
until ($script:test)
}
else {
$script:test = new-object System.IO.FileStream $fileOpenArgs
}

"Acquired lock, sleeping 30 seconds"
Start-Sleep 30
"Done"

Cleanup


BTW since we have full access to the .NET Framework you are not limited to using files for locks. You could also use a System.Threading.Mutex for inter-process locking. I'm not saying you should - just pointing out that the option exists.

--
Keith

Loading...