Java FileChannel keeps locking file - java

Hope someone can shed some light into what I'm doing wrong.
I have a DataLoader class that creates a FileInputStream. Since FileInputStream implements Closeable, I create that instance as part of the try block.
I then pass the newly created stream to a DataManager class. This class opens a file channel and reads data into a singleton class, storing all data into memory blocks. Since FileChannel also implements Closeable, I also instanciate it in the try block
I then invoke this code from a single thread to check every now if there are any filechanges, and when this happens, a new instance of DataLoader is created to rebuild the memory blocks. But this constantly fails due to file locking. This code is part of a Java 1.8 standard application, running on windows 10. Am I assuming wrongly that both file channel and file inputstream close? I added code to invoke the close method in both classes, but with no success. Any help would be greatly appreciated. Thanks in advance.
public class DataManager {
public DataManager(FileInputStream in) throws IOException {
fromInputStream(in);
}
public final void fromInputStream(FileInputStream in) throws IOException {
try (FileChannel ch = in.getChannel()) {
MappedByteBuffer mb = ch.map(MapMode.READ_ONLY, ch.position(), ch.size());
readData(mb); //reads mapped buffer into a byte array, e.g.: mb.get(barray, 0, 1000);
}
}
}
public class DataLoader {
public DataLoader(File binFile) throws FileNotFoundException, IOException {
try (FileInputStream in = new FileInputStream(binFile)) {
DataManager d = new DataManager(in);
} catch (Exception e) {
LOG.error("Something went wrong while loading data.", e);
}
}
}

As suggested in the comments, the issue relies on windows being somewhat stringent regarding the use of FileChannel. I replaced all FileChannel related code with InputStream and the locking behavior disappeared.

Related

How does java.util.logging.Handler lifecycle works?

I'm trying to implement a custom handler that logs parsed LogRecord objects into a file (basically what FileHandler or StreamHandler does). My currently implementation is shown below:
public final class ErrorHandler extends Handler {
private static final String OUTPUT_FILE = ".output";
private final Formatter formatter = new CustomFormatter();
private BufferedWriter writter;
#Override
public void publish(LogRecord record) {
if (record.getLevel() == SEVERE || record.getLevel() == WARNING) {
writeToOutput(record);
}
}
void writeToOutput(LogRecord log) {
try {
if (writter == null) {
writter = new BufferedWriter(new FileWriter(OUTPUT_FILE, true));
}
writter.write(formatter.format(log));
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void flush() {
}
#Override
public void close() {
try {
writter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
P.S.: I known that we can achieve the same as the code above just by setting filter and formatter on a FileHandler or StreamHandler however I'll need the hookpoints later in the future.
My problem is, if I leave flush() with no implementation, although output file gets created, no log is written there. If I call writter.flush() inside flush(), the log is duplicated. Any though why this might be happening?
Ok, after two days fighting agains that I came to realize that the process was running on a daemon, therefore, handler's close() was only called when daemon was killed. I believe that this was leading to multiples calls to flush() almost at the same time. Running the process with no daemon solved the issue.
My problem is, if I leave flush() with no implementation, although output file gets created, no log is written there.
This is because the bytes are cached in the BufferedWriter. Flush sends those bytes to the wrapped FileWriter. If you collect enough bytes it will flush to the target file but you risk losing that information of you have some sort of process crash or disk issue.
If I call writter.flush() inside flush(), the log is duplicated. Any though why this might be happening?
Perhaps you have added two instances of this handler to the logger and both are appending to the same file. Logger.addHandler works like a List and not like a Set. Add code to Print the logger tree which will tell you how many handler instances are installed.
I'm sure I have no process crash nor disk issue, and I believe that close calls flush. Yet, I don't see why nothing is being logged - and it happens only file is not created yet.
Close is only implicitly called when the Java virtual machine shuts down and the handler is visible from the LogManager. If the shutdown is not clean as described in the documentation then the contents of the buffered writer is not flushed.

What is the best way to emulate try-with-resources in Java 6?

It turns out that almost nobody closes resources in Java correctly. Programmers either do not use try-finally block at all, or just put resource.close() in finally which is also incorrect (because Throwable from close() can shadow Throwable from try block). Sometimes they put something like IOUtils.closeQuietly() with is only correct for InputStream, but not for OutputStream. try-with-resources solves all of these problems but there are still huge number of projects written in Java 6.
What is the best way to emulate try-with-resources in Java 6? Now I use Guava Closer, which is better than nothing but still much uglier than try-with-resources. Also, there is a pattern called a loan-pattern, but the absence of lambdas in Java makes this pattern very cumbersome. Is there a better way?
I've found a good replacement for try-with-resources. It uses Lombok library with annotation processing:
#Cleanup InputStream in = new FileInputStream(args[0]);
#Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
However, it doesn't handle exception correctly. This bug is more than 1 year old and still is not closed: https://code.google.com/p/projectlombok/issues/detail?id=384
Though anonymous class is quite verbose, it's still acceptable in java land
new TryWithResource<InputStream>(){
protected InputStream init() throws Exception {
return new FileInputStream("abc.txt");
}
protected void use(InputStream input) throws Exception{
input.read();
}
};
----
abstract class TryWithResource<R>
{
abstract protected R init() throws Exception;
abstract protected void use(R resource) throws Exception;
// caution: invoking virtual methods in constructor!
TryWithResource() throws Exception
{
// ... code before
R r = init();
use(r);
// ... code after
}
}
If your only problem with IOUtils.closeQuietly is that it ignores exceptions on OutputStreams, then you can either simply call close() on them, or create your own utility class which automatically treats the two differently, like this:
public static void close(Closeable resource)
{
try
{
resource.close();
}
catch(Exception e)
{
//swallow exception
}
}
public static void close(OutputStream o)
{
//throw any exceptions
o.close();
}
The correct overloaded method will be selected at compile time in all common situations, although if you're passing OutputStreams around as Closeables then you'll have to change this to do a dynamic instanceof check to make sure OutputStreams always throw exceptions.

Java Try With Resources Does Not Work For Assignment?

Alright, so I was just writing a quick class and I tried to use the try with resources instead of the try-catch-finally (hate doing that) method and I keep getting the error "Illegal start of type". I then turned to The Java Tutorials section on it: http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html and it showed that you can assign a new variable in the parenthesis. I'm not sure what is going on.
private static final class EncryptedWriter {
private final Path filePath;
private FileOutputStream outputStream;
private FileInputStream inputStream;
public EncryptedWriter(Path filePath) {
if (filePath == null) {
this.filePath = Paths.get(EncryptionDriver.RESOURCE_FOLDER.toString(), "Encrypted.dat");
} else {
this.filePath = filePath;
}
}
public void write(byte[] data) {
try (this.outputStream = new FileOutputStream(this.filePath.toFile())){
} catch (FileNotFoundException ex) {
Logger.getLogger(EncryptionDriver.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
This is not how try-with-resources work. You have to declare the OutputStream there only. So, this would work:
try (FileOutputStream outputStream = new FileOutputStream(this.filePath.toFile())){
The whole point of try-with-resources is to manage the resource itself. They have the task of initializing the resource they need, and then close it when the execution leaves the scope. So, it doesn't make sense for it to use the resource declared else where. Because it wouldn't be right to close the resource which it hasn't opened, and then the issue with the old try-catch is back.
The very first line of that tutorial clearly states this thing:
The try-with-resources statement is a try statement that declares one or more resources.
... and declaration is different from initialization or assignment.

How to get the progress of reading a file

I'm trying to read a large object from a file in my application. Since this can take some time I'd like to somehow connect the reading of the file with a JProgressBar. Is there any easy way to find the progress of reading a file? (The loading itself is done in a swingworker thread so updating a progress bar should not be a problem.) I've been thinking about overriding the readByte() method in the FileInputStream to return a progress value of sorts but that seems such a devious way. Any suggestions on how to realize this are more than welcome.
Here is the code for reading the file:
public class MapLoader extends SwingWorker<Void, Integer> {
String path;
WorldMap map;
public void load(String mapName) {
this.path = Game.MAP_DIR + mapName + ".map";
this.execute();
}
public WorldMap getMap() {
return map;
}
#Override
protected Void doInBackground() throws Exception {
File f = new File(path);
if (! f.exists())
throw new IllegalArgumentException(path + " is not a valid map name.");
try {
FileInputStream fs = new FileInputStream(f);
ObjectInputStream os = new ObjectInputStream(fs);
map = (WorldMap) os.readObject();
os.close();
fs.close();
} catch (IOException | ClassCastException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void done() {
firePropertyChange("map", null, map);
}
}
If it were me, I would not mess with overriding FileInputStream. I think the decorator might be a good fit here. The idea is you create a decorator input stream that you pass to your ObjectInputStream. The decorator takes care of updating the progress of your read, then delegates to the real input stream.
Perhaps the easiest solution is to use CountingInputStream from Apache commons-io. The basic steps would be:
Create subclass of CountingInputStream as a non-static inner class of your map loader
Override the afterRead method. Call super.afterRead, then publish your updated status
Pass an instance of your new decorator input stream to output stream, passing the file input stream to the constructor of your decorator
Using RandomAccessFile you may call getFilePointer() to known how many bytes was read.
Time consuming operation may be executed in a background thread, remember using SwingUtilities.invokeLater() to communicate between background task and GUI threads.
If you are considering to override read() in FileInputStream, what you could legitimately consider is making your own wrapper InputStream class that accepts a progress-monitor callback. However, you'll find out that it not as easy as implementing read() since it is very inefficient to spend a method invocation for each byte. Instead you'll need to deal with read(byte[], int, int), which is a bit more involved.

BufferedWriter - Stream closed prematurely during program execution

I am defining a buffered writer in a class I am developing, but having problems with it.
In the class constructor I am defining:
public class RestHandler {
public static BufferedWriter rest_logger;
public RestHandler(parsedXMLConfigData _config, BufferedWriter writer) {
rest_logger = writer;
try {
rest_logger.write("RestHandler instance finished init and ready to receive calls!" + "\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This works and prints the text to my file. But when I try to use the same rest_logger in another one of my class methods:
#POST
#Path("{subResources: [a-zA-Z0-9_/]+}")
public void postHandler
(
#Context final UriInfo uriInfo,
#PathParam("subResources") String subResources) {
try {
rest_logger.write("TEXT...");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It gives me a stream closed exception! I should mention that I use this to close the stream:
protected void finalize() throws Throwable {
rest_logger.close();
}
There are several problems with your code:
the rest_logger variable should not be static
you shouldn't initialize it to a new BufferedWriter just to discard it afterwards and reinitialize it with the writer argument (that you have no control on)
you shouldn't ignore exceptions. If you don't know what to do with them, make your methods throw IOException and let the caller decide what to do
you should not use finalizers
you should not close a writer that you have not created. Let the opener of the writer close it.
Other than that, and since your code doesn't make much sense, it's hard to understand what the code is supposed to do.
Removing the exception handlers for clarity, your code does:
rest_logger = new BufferedWriter(new FileWriter("rest_logger.txt"));
rest_logger = writer;
You're throwing away that new BufferedWriter immediately there. It does not make much sense. rest_logger will be set to whatever was handed over to you in that constructor call. When that gets closed, rest_logger will be closed too.
I'm not quite sure I understood your question, BUT:
why exactly are you overwriting your newly created BufferedWriter?
rest_logger = writer;
maybe you should look into that...

Categories