Issues with multiple FileOutputStreams to the same file in Java - java

I'm trying to write to a file using FileOutputStream. When the user selects what file to write to, the program tries to create a FileOutputStream using that file, to check if it works. If it does not, the user has to select a different file. If it does work, the FileOutputStream is closed.
After a file, for which a FOS can be opened, has been selected the program tries again to create another FOS, but this sometimes fails.
I know that you cannot write to a file when it is open on your computer. Could it be that the first FOS has not been "fully closed" and therefore the file is still considered open, so that the second FOS can not write to it?
In the following code, what happens is that the first creation and closing of the FOS does not throw an exception, while the second one somehow does. How can this be?
(I know the problem can be solved by simply using the first FOS and not creating a second, but I am interested in understanding why this particular code behaves the way it does.)
try {
FileOutputStream out1 = new FileOutputStream(file);
out1.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
FileOutputStream out2 = new FileOutputStream(file);
} catch (Exception e) {
e.printStackTrace();
}

Based on the symptoms, I surmise that you are using Windows, and the error you are getting in the second open is "file is in use".
Apparently under some circumstances, Windows does not immediately close a file when the application (in this case the JVM) closes the FileHandle:
FileStream.Close() is not closing the file handle instantly
Delay between CloseHandle function call and SMB Close request
This is not Java's doing, and I am not aware of a workaround (in Java) apart from waiting a bit and retrying.
(You could see what happens if you add a Thread.sleep(1000); before the 2nd attempt to create a FileOutputStream.)

Related

ZipInputStream is closes when reading first ZipEntry of Excel files

I'm uploading zip of excel files as multipart file, but when I create Workbook object of first file, the stream gets closed and I'm not able to read next files.
its working with single file in zip but not with multiple files.
can anybody help? TIA.
try {
ZipInputStream zis = new ZipInputStream(multipartFile.getInputStream());
ZipEntry zipEntry;
while((zipEntry = zis.getNextEntry()) != null) {
XSSFWorkbook workbook = new XSSFWorkbook(zis);
readWorkbook(workbook);
}
zis.close();
} catch (Exception e) {
LOG.error(e);
}
only option is to wrap it so you can intercept close() and prevent it from closing the zip. Something like:
var wrapper = new FilterInputStream(zis) {
#Override public void close() {}
}
Then pass wrapper and not zis to new XSSFWorkbook.
NB: WARNING - your code is severely hampered, essentially buggy. You need to ensure you close that ZipInputStream at the very end, and you're not doing that now. Your exception handling is really bad. You must end all exception blocks with a hard exit, just logging it isn't good enough. throw new RuntimeException("uncaught", e); is the fallback option (many IDEs ship with e.printStackTrace() as default. This is a known extremely stupid default, update your IDE to fix this. Use try-with-resources as well to ensure closing always happens (just calling close() isn't good enough; that close() call you do have in your snippet won't be invoked if exceptions occur.
When reading from a Zipfile, you have an InputStream for the archive. Then you traverse the different entries in there and for each of them you again have an InputStream to read from. Make sure you do not close the entries' InputStreams as that event will close the archive stream.
In your case it may be that the constructor for XSSFWorkbook or the readWorkbook method is closing the stream.

Rollback or Reset a BufferedWriter

A logic that handles the rollback of a write to a file is this possible?
From my understanding a BufferWriter only writes when a .close() or .flush() is invoked.
I would like to know is it possible to, rollback a write or undo any changes to a file when an error has occurred?
This means that the BufferWriter acts as a temporary storage to store the changes done to a file.
How big is what you're writing? If it isn't too big, then you could write to a ByteArrayOutputStream so you're writing in memory and not affecting the final file you want to write to. Only once you've written everything to memory and have done whatever you want to do to verify that everything is OK can you write to the output file. You can pretty much be guaranteed that if the file gets written to at all, it will get written to in its entirety (unless you run out of disk space.). Here's an example:
import java.io.*;
class Solution {
public static void main(String[] args) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
// Do whatever writing you want to do here. If this fails, you were only writing to memory and so
// haven't affected the disk in any way.
os.write("abcdefg\n".getBytes());
// Possibly check here to make sure everything went OK
// All is well, so write the output file. This should never fail unless you're out of disk space
// or you don't have permission to write to the specified location.
try (OutputStream os2 = new FileOutputStream("/tmp/blah")) {
os2.write(os.toByteArray());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you have to (or just want to) use Writers instead of OutputStreams, here's the equivalent example:
Writer writer = new StringWriter();
try {
// again, this represents the writing process that you worry might fail...
writer.write("abcdefg\n");
try (Writer os2 = new FileWriter("/tmp/blah2")) {
os2.write(writer.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
It is impossible to rollback or undo changes already applied to files/streams,
but there are tons of alternatives to do so:
One simple trick is to clean the destination and redo the process again, to clean the file:
PrintWriter writer = new PrintWriter(FILE_PATH);
writer.print("");
// other operations
writer.close();
You can remove the content entirely and re-run again.
Or if you are sure the last line(s) are the problems, you may do remove last line actions for your purpose, such as rollback the line instead:
Delete last line in text file

Closing a FileOutputStream in java without a reference to it?

In java, we can do the following:
new FileOutputStream(new File("dir"));
(Excluding the exception handling for talks sake).
Should we somehow close the stream in this instance? if so how do we do it? if we don't create a local reference within a method for example:
FileOutputStream fos = new FileOutputStream(new File("dir"));
Is it bad practice to handle a stream shown in the first example? does java handle / close itself in that instance?
I receive some poor static code analysis when using the
foo = new FileOutputStream(new File("dir"));
because the stream is not closed, but I can't get a handle to close it? or maybe I can and i'm just not aware how.
Thank you all for the feedback, my apologies on not making my example relevant and clear. please see my actual code below:
public void generateEnvironmentProperties() {
Properties props = new Properties();
properties.getAllProperties().forEach((k,v) -> props.setProperty(k,v));
try {
File f = new File("target\\allure-results\\environment.properties");
if (!f.getParentFile().mkdirs()) {
throw new IOException("Unable to create file(s)");
}
if (!f.createNewFile()) {
throw new IOException("Unable to create file(s)");
}
props.store(new FileOutputStream(f), "Allure Environment Properties");
} catch(IOException ioe) {
LOG.fatal(ioe);
}
}
As the Properties.store javadoc says:
After the entries have been written, the output stream is flushed.
The output stream remains open after this method returns.
So it is indeed required that you hold on to the instance of FileOutputStream you're using and close it yourself.
you can use try-with-resources, one of the Java 7 feature
try(FileOutputStream fos = new FileOutputStream(f)){
// use resources, for example:
props.store(fos , "Allure Environment Properties");
} catch (FileNotFoundException e) {
// exception handling, for example:
LOG.fatal(ioe);
}
the resources are closed as soon as the try-catch block is executed
props.store(new FileOutputStream(f), "Allure Environment Properties");
DON'T DO THIS. As your IDE warns you, the output stream will not be closed. You have two options:
Keep a reference to the stream and close it yourself. You will need to write the correct try...catch...finally statement to make sure the stream is closed even if an exception is thrown.
If you are using Java 7 or later, use try with resources. This new form of the try...catch statement will automatically close a stream when the try block exists.

How to check whether file is open or not in java [duplicate]

I need to write a custom batch File renamer. I've got the bulk of it done except I can't figure out how to check if a file is already open. I'm just using the java.io.File package and there is a canWrite() method but that doesn't seem to test if the file is in use by another program. Any ideas on how I can make this work?
Using the Apache Commons IO library...
boolean isFileUnlocked = false;
try {
org.apache.commons.io.FileUtils.touch(yourFile);
isFileUnlocked = true;
} catch (IOException e) {
isFileUnlocked = false;
}
if(isFileUnlocked){
// Do stuff you need to do with a file that is NOT locked.
} else {
// Do stuff you need to do with a file that IS locked
}
(The Q&A is about how to deal with Windows "open file" locks ... not how implement this kind of locking portably.)
This whole issue is fraught with portability issues and race conditions:
You could try to use FileLock, but it is not necessarily supported for your OS and/or filesystem.
It appears that on Windows you may be unable to use FileLock if another application has opened the file in a particular way.
Even if you did manage to use FileLock or something else, you've still got the problem that something may come in and open the file between you testing the file and doing the rename.
A simpler though non-portable solution is to just try the rename (or whatever it is you are trying to do) and diagnose the return value and / or any Java exceptions that arise due to opened files.
Notes:
If you use the Files API instead of the File API you will get more information in the event of a failure.
On systems (e.g. Linux) where you are allowed to rename a locked or open file, you won't get any failure result or exceptions. The operation will just succeed. However, on such systems you generally don't need to worry if a file is already open, since the OS doesn't lock files on open.
// TO CHECK WHETHER A FILE IS OPENED
// OR NOT (not for .txt files)
// the file we want to check
String fileName = "C:\\Text.xlsx";
File file = new File(fileName);
// try to rename the file with the same name
File sameFileName = new File(fileName);
if(file.renameTo(sameFileName)){
// if the file is renamed
System.out.println("file is closed");
}else{
// if the file didnt accept the renaming operation
System.out.println("file is opened");
}
On Windows I found the answer https://stackoverflow.com/a/13706972/3014879 using
fileIsLocked = !file.renameTo(file)
most useful, as it avoids false positives when processing write protected (or readonly) files.
org.apache.commons.io.FileUtils.touch(yourFile) doesn't check if your file is open or not. Instead, it changes the timestamp of the file to the current time.
I used IOException and it works just fine:
try
{
String filePath = "C:\sheet.xlsx";
FileWriter fw = new FileWriter(filePath );
}
catch (IOException e)
{
System.out.println("File is open");
}
I don't think you'll ever get a definitive solution for this, the operating system isn't necessarily going to tell you if the file is open or not.
You might get some mileage out of java.nio.channels.FileLock, although the javadoc is loaded with caveats.
Hi I really hope this helps.
I tried all the options before and none really work on Windows. The only think that helped me accomplish this was trying to move the file. Event to the same place under an ATOMIC_MOVE. If the file is being written by another program or Java thread, this definitely will produce an Exception.
try{
Files.move(Paths.get(currentFile.getPath()),
Paths.get(currentFile.getPath()), StandardCopyOption.ATOMIC_MOVE);
// DO YOUR STUFF HERE SINCE IT IS NOT BEING WRITTEN BY ANOTHER PROGRAM
} catch (Exception e){
// DO NOT WRITE THEN SINCE THE FILE IS BEING WRITTEN BY ANOTHER PROGRAM
}
If file is in use FileOutputStream fileOutputStream = new FileOutputStream(file); returns java.io.FileNotFoundException with 'The process cannot access the file because it is being used by another process' in the exception message.

delete temporary file in java

I'm creating temporary file in java but i'm unable to delete it. This is the code I have written:
temp = File.createTempFile("temp", ".txt");
temp.deleteOnExit();
fileoutput = new FileWriter(temp);
buffout = new BufferedWriter(fileoutput);
Add the following code (after you have done your operations with the file):
buffout.close();
fileoutput.close();
temp.delete();
As long as some stream on the file is open, it is locked (at least on the windows-implementation of the JVM). So it cannot be deleted.
It is good practice always to check if all opened streams get closed again after usage, because this is a bad memory-leak-situation. Your application can even eat up all available file-handles, that can lead to an unusable system.
There's a bug saying that if the file is open by filewriter or anything, it won't be deleted. On windows. Check if you close your file writers.
Another workaround would be installing a ShutdownHook which would manually delete the file.
You have to shut down a VM cleanly in order for the deleteOnExit to work properly (I suspect). On UNIX a kill would be a clean shutdown (i.e. the ShutdownHooks would be processed) whereas a kill -9 would be more like a force quit.
deleteOnExit definitely works for me!
Code to close the inpustream and outputstream:
FileInputStream in = new FileInputStream();
ArrayList list_in = new ArrayList<FileInputStream>();
list_in.add(in);
FileOutputStream out = new FileOutputStream();
ArrayList list_out = new ArrayList<OutputputStream>();
list_in.add(out);
public do_before_exit()
{
for(int i=0;i<list_in.size();i++)
{
FileInputStream in=(FileInputStream)list_in.get(i)
FileInputStream out=(FileInputStream)list_out.get(i)
in.close()
out.close();
}
}

Categories

Resources