Lock a file or somehow make it unwritable

  • Thread starter Lionel van den Berg
  • Start date
L

Lionel van den Berg

I'm building a test harness and would like to lock a particular file
so that when the system under test tries to write to this file it
cannot. I was looking at FileChannel but (un)fortunately that locks it
for the entire VM, so it doesn't affect any later calls.

Any ideas on solutions?

thanks

Lionel.
 
A

Arne Vajhøj

Lionel said:
I'm building a test harness and would like to lock a particular file
so that when the system under test tries to write to this file it
cannot. I was looking at FileChannel but (un)fortunately that locks it
for the entire VM, so it doesn't affect any later calls.

Any ideas on solutions?

Have you tried opening it for write as a lock?

Arne
 
L

Lionel van den Berg

Have you tried opening it for write as a lock?

Yes, here is a sample of the code I have tried:

final File file = new File(filePath);
// Create the file or we won't get a lock.
file.createNewFile();

final FileOutputStream fileOutputStream = new FileOutputStream(file);
final FileLock fileLock = fileOutputStream.getChannel().lock();

if (fileLock == null) {
writeString("Failed to acquire lock on \"" + filePath + "\".");
} else {
fileLocks.add(fileLock);
}

But when you look at the documentation for FileChannel the following
gives away the secret:

"File locks are held on behalf of the entire Java virtual machine.
They are not suitable for controlling access to a file by multiple
threads within the same virtual machine. "
 
J

Joshua Cranmer

Lionel said:
"File locks are held on behalf of the entire Java virtual machine.
They are not suitable for controlling access to a file by multiple
threads within the same virtual machine. "

Execute the locking in another JVM instance?
 
L

Lionel van den Berg

Execute the locking in another JVM instance?

Definitely a possibility, though it is a bit of extra work. I am
considering this, was hoping a better solution would be available.
 
R

Roedy Green

I'm building a test harness and would like to lock a particular file
so that when the system under test tries to write to this file it
cannot. I was looking at FileChannel but (un)fortunately that locks it
for the entire VM, so it doesn't affect any later calls.

Some approaches:

1. allow only one thread to access the file. Ask that thread when you
need to do I/O. Use one of the java.util.concurrent work packet queue
classes.

2. use a 1-byte busy indicator file. When it it exists, the main file
is in use.

3. put the data is an SQL database and let the SQL engine deal with
the concurrency
 
L

Lionel van den Berg

Some approaches:

1. allow only one thread to access the file.  Ask that thread when you
need to do I/O. Use one of the java.util.concurrent work packet queue
classes.

2. use a 1-byte busy indicator file.  When it it exists, the main file
is in use.

3. put the data is an SQL database and let the SQL engine deal with
the concurrency


Not sure if I stated the requirements correctly. This is purely for
testing purposes so the program that I'm testing should not be
changed, this pretty much rules out all of the solutions (though nice
solutions in another circumstance).

I have however managed to achieve what I want to achieve by setting
the file to read only.

Just in case you are curious, the full reason I wanted to do this is
that I have a program that I want to test, this program will create a
text file (let's call it TextFile.txt) and write data to it. Of course
there is error handling in case it can't create that file or write to
it, I want to test that it handles the error case correctly, I already
had some test infrastructure so it made sense to add the feature of
locking a file (TextFile.txt) so that when the program tried to write
to it, it could not. As I have now said, it can be achieved by doing:

final File file = new File("TextFile.txt");
file.createNewFile();
file.setReadOnly();

// Rest of test frame work.

Thanks for the help.

Lionel.
 
A

Arne Vajhøj

Lionel said:
Yes, here is a sample of the code I have tried:

final File file = new File(filePath);
// Create the file or we won't get a lock.
file.createNewFile();

final FileOutputStream fileOutputStream = new FileOutputStream(file);
final FileLock fileLock = fileOutputStream.getChannel().lock();

if (fileLock == null) {
writeString("Failed to acquire lock on \"" + filePath + "\".");
} else {
fileLocks.add(fileLock);
}

But when you look at the documentation for FileChannel the following
gives away the secret:

"File locks are held on behalf of the entire Java virtual machine.
They are not suitable for controlling access to a file by multiple
threads within the same virtual machine. "

Your original question stated that you wanted to prevent the
test code from writing to the file.

I can not really see how the above correlates to that.

But anyway.

Some experimentation shows that FileOutputStream does
not lock the file exclusively.

But .getChannel().lock() as in your code works (if used
for locking and not for test).

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io_OutputStream;
import java.nio.channels.FileLock;

public class Lock {
public static OutputStream uselessLock(File f) throws IOException {
return new FileOutputStream(f, true);
}
public static FileLock workingLock(File f) throws IOException {
return new FileOutputStream(f, true).getChannel().lock();
}
public static void main(String[] args) throws Exception {
File f = new File("C:\\z.z");
f.createNewFile();
//uselessLock(f);
workingLock(f);
OutputStream os = new FileOutputStream(f, true);
os.write(123);
os.close();
}
}

did result in:

Exception in thread "main" java.io.IOException: The process cannot
access the file because another process has locked a portion of the file

which I assume is what you want.

Arne
 
L

Lionel van den Berg

Lionel van den Berg wrote:










Your original question stated that you wanted to prevent the
test code from writing to the file.

I've re-read my original post and I can't really come to that
conclusion:

"so that when the system under test tries to write to this file it
cannot"

The system under test, not the test code.

Anyway, there was obviously confusion that's why I restated.

I can not really see how the above correlates to that.

Nor can I see how you came to your interpretation.
But anyway.

Definitely :).

Some experimentation shows that FileOutputStream does
not lock the file exclusively.

But .getChannel().lock() as in your code works (if used
for locking and not for test).

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io_OutputStream;
import java.nio.channels.FileLock;

public class Lock {
     public static OutputStream uselessLock(File f) throws IOException {
         return new FileOutputStream(f, true);
     }
     public static FileLock workingLock(File f) throws IOException {
         return new FileOutputStream(f, true).getChannel().lock();
     }
     public static void main(String[] args) throws Exception {
         File f = new File("C:\\z.z");
         f.createNewFile();
         //uselessLock(f);
         workingLock(f);
         OutputStream os = new FileOutputStream(f, true);
         os.write(123);
         os.close();
      }

}

did result in:

Exception in thread "main" java.io.IOException: The process cannot
access the file because another process has locked a portion of the file

which I assume is what you want.

It's exactly what I want which confuses me to why it didn't work the
way I was using it. But doesn't that behaviour violate the Javadoc
statement? http://java.sun.com/javase/6/docs/api/

again:

"File locks are held on behalf of the entire Java virtual machine.
They are not suitable for controlling access to a file by multiple
threads within the same virtual machine. "

This isn't even multiple threads, doesn't that say it should not work,
or does it suggest that you can't trust it to work?

I'm going to go back and try again - although my solution is working,
I might actually want to do it both ways.

Thanks

Lionel.
 
L

Lew

Lionel said:
"File locks are held on behalf of the entire Java virtual machine.
They are not suitable for controlling access to a file by multiple
threads within the same virtual machine. "

But multiple threads in the same JVM have an advantage - they can use some
common datum cooperatively to achieve non-concurrent access to a file.
 
L

Lionel van den Berg

Lionel van den Berg wrote:
Some experimentation shows that FileOutputStream does
not lock the file exclusively.

But .getChannel().lock() as in your code works (if used
for locking and not for test).

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io_OutputStream;
import java.nio.channels.FileLock;

public class Lock {
     public static OutputStream uselessLock(File f) throws IOException {
         return new FileOutputStream(f, true);
     }
     public static FileLock workingLock(File f) throws IOException {
         return new FileOutputStream(f, true).getChannel().lock();
     }
     public static void main(String[] args) throws Exception {
         File f = new File("C:\\z.z");
         f.createNewFile();
         //uselessLock(f);
         workingLock(f);
         OutputStream os = new FileOutputStream(f, true);
         os.write(123);
         os.close();
      }

}

did result in:

Exception in thread "main" java.io.IOException: The process cannot
access the file because another process has locked a portion of the file

which I assume is what you want.


This is interesting. I tried you example, and it works as you said,
however, if you use a PrintStream as follows, there is no exception
and the text is not written:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.channels.FileLock;

/**
*
*/
public class Main {

public static FileLock workingLock(File f) throws IOException {
return new FileOutputStream(f, true).getChannel().lock();
}
public static void main(String[] args) throws Exception {
File f = new File("C:\\Test.txt");
f.createNewFile();
workingLock(f);
PrintStream ps = new PrintStream(f);
ps.print("Test");
ps.close();
}
}
 
L

Lionel van den Berg

But multiple threads in the same JVM have an advantage - they can use some
common datum cooperatively to achieve non-concurrent access to a file.

I don't have a problem with the claimed implementation, but seems the
implementation does not follow the documentation? I must be missing
something.
 
L

Lionel van den Berg

Lionel van den Berg wrote:
...> This is interesting. I tried you example, and it works as you said,

...

That is a documented feature of PrintStream: "Unlike other output
streams, a PrintStream never throws an IOException; instead, exceptional
situations merely set an internal flag that can be tested via the
checkError method."

Well spotted.



I think you meant http://java.sun.com/javase/6/docs/api/java/io/PrintStream..html

Cheers

Lionel.
 
L

Lionel van den Berg

Lionel van den Berg wrote:
...> This is interesting. I tried you example, and it works as you said,

...

That is a documented feature of PrintStream: "Unlike other output
streams, a PrintStream never throws an IOException; instead, exceptional
situations merely set an internal flag that can be tested via the
checkError method."

Well spotted.



I think you meant http://java.sun.com/javase/6/docs/api/java/io/PrintStream..html

Cheers

Lionel.
 
A

Arne Vajhøj

Lionel said:
I've re-read my original post and I can't really come to that
conclusion:

"so that when the system under test tries to write to this file it
cannot"

The system under test, not the test code.

Anyway, there was obviously confusion that's why I restated.


Nor can I see how you came to your interpretation.

You were talking about creating a situation where
attempting to write to a file is not possible.

You test code tries to acquire a lock instead of writing.

I can not see how the test related to your stated goal.
Some experimentation shows that FileOutputStream does
not lock the file exclusively.

But .getChannel().lock() as in your code works (if used
for locking and not for test).

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io_OutputStream;
import java.nio.channels.FileLock;

public class Lock {
public static OutputStream uselessLock(File f) throws IOException {
return new FileOutputStream(f, true);
}
public static FileLock workingLock(File f) throws IOException {
return new FileOutputStream(f, true).getChannel().lock();
}
public static void main(String[] args) throws Exception {
File f = new File("C:\\z.z");
f.createNewFile();
//uselessLock(f);
workingLock(f);
OutputStream os = new FileOutputStream(f, true);
os.write(123);
os.close();
}

}

did result in:

Exception in thread "main" java.io.IOException: The process cannot
access the file because another process has locked a portion of the file

which I assume is what you want.

It's exactly what I want which confuses me to why it didn't work the
way I was using it. But doesn't that behaviour violate the Javadoc
statement? http://java.sun.com/javase/6/docs/api/

again:

"File locks are held on behalf of the entire Java virtual machine.
They are not suitable for controlling access to a file by multiple
threads within the same virtual machine. "

This isn't even multiple threads, doesn't that say it should not work,
or does it suggest that you can't trust it to work?

I'm going to go back and try again - although my solution is working,
I might actually want to do it both ways.

I think it means that the Java specs does not guarantee that
the locking technique above will work.

But there are very few guarantees about the locking stuff at
all, because it is so OS specific.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top