Java try with resources with Reader and Writer on the same file - java

try (Reader reader = Files.newBufferedReader(path);
Writer writer = Files.newBufferedWriter(path)) {
...
} catch (IOException exception) {
...
}
Can I use Reader and Writer which open the same file in try-with-resources? Is it safe?

Even if it's allowed, it's just waiting for problems to occur. Reader and Writer are not meant to work on the same file.
There are alternatives that you can look into. Good old RandomAccessFile is created to support both reading and writing. It's not great for text though. FileChannel, accessible from a RandomAccessFile or using FileChannel.open is newer but still doesn't work well with text.

This would be a bad practice. Different operating system will give you inconsistent results and it's asking for problems.
You'd be better off reading the file, writing to a temporary file, then replacing the old file with the temporary file when you're done.

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.

Lock the file in java

How can I lock the file in JVM in such way that other non JVM processes can't get access for write access?
I need to read the file and while reading I want to be sure that other processes do not modify the file.
I tried creating FileInputStream and it does lock the file for deleting but it doesn't prohibit the modification of file.
I also tried RandomAccessFile:
RandomAccessFile raf = new RandomAccessFile(file, "rw");
InputStream is = Channels.newInputStream(raf.getChannel());
but it also doesn't prevent modifications.
PS: Further in the code I need InputStream
Unfortunately, this is not something Java can do - perhaps largely because it is supported in different ways on different platforms and Java needs to maintain cross platform compatibility.
I assume, from your question for example, that you are on Windows as under Linux the above code would not even prevent file deletion.
There is some detailed information on file locking at http://en.wikipedia.org/wiki/File_locking which explains the issue.
Have you tried to use FileLock? The usage will be like this snippet:
FileInputStream in = new FileInputStream(file);
try {
java.nio.channels.FileLock lock = in.getChannel().lock();
try {
Reader reader = new InputStreamReader(in, charset);
//Other actions...
} finally {
lock.release();
}
} finally {
in.close();
}

'try with resource' feature for File class

I have one scenario where I am trying to implement with the Java 7 'try with resource' feature.
My finally block contains an object of BufferedWriter and File, which I want to close using 'try with resource' feature, instead of closing it by calling close method explicitly.
But I checked on net and saw that the File class does not implement the AutoCloseable interface, but BufferedWriter does. So how can I manage this scenario to implement 'try with resource' feature?
try (BufferedWriter br = new BufferedWriter(new FileWriter(path)))
Use this simply, br will be closed automatically.
Eg. http://www.roseindia.net/java/beginners/java-write-to-file.shtml
You don't need to close a File because it's a pure Java object. It basically just holds the name of the file, nothing else (i.e. it does not require any OS resources to construct).
You only need to close your BufferedWriter and that is correctly AutocCloseable.
You cannot create a BufferedWriter with File only, BufferedWriter requires a Writer, this how it should look like
try (BufferedWriter w = new BufferedWriter(new FileWriter(new File("file")))) {
...
}
try-with-resources will call close only on BufferedWriter. Unfortunately BufferedWriter API does say that it closes the underlying writer, but in fact it does. As for File it has nothing to do with try-with-resources since it is not Autocloseable.

Android - Append Specfic Line In A Text File

hey people,
I have a text file which I need to append in my app. Now I could rewrite the entire file incorporating the changes to a specific line but I'm hoping there is a more efficient solution.
I know the line number I need to append however I'm unsure how to get to that line, preferably without looping through all of the others unless that is the only way. This is what I have so far which recreates the entire file:`
try {
FileOutputStream fOut = openFileOutput("tasklist.txt", MODE_APPEND);
BufferedOutputStream buf = new BufferedOutputStream(fOut);
OutputStreamWriter osw = new OutputStreamWriter(buf);
BufferedWriter writer = new BufferedWriter(osw);
for(int count = 0; count < str.size(); count++)
{
writer.write(str[count]);
writer.write("\r\n");
}
writer.flush();
writer.close();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "Error saving txt file", Toast.LENGTH_SHORT);
}`
Hopefully someone knows of a more efficient solution. Thanks.
There are some cleaner ways, but with file handling there isn't really a more efficient way (that I know of). You basically go from start to finish, as you have done, and append data. That's how file I/O works (it's not an Android or Java thing).
Still, you could try FileWriter to tidy it up a bit (the "true" param to the ctor means append):
FileWriter writer = new FileWriter(aFile, true));
try {
writer.write("append here\n");
} finally {
writer.close();
}
Be advised though, FileWriter uses the systems default encoding. This should be fine on Android, but be careful with it in general.
Here are some good general practices for dealing with reading and writing files with Java.
Also, depending on what you're doing with this file you're appending to (how often you are editing the same file, and from what processes), you may need to make a copy of it, and or deal with fysnc, to make sure you don't lose data on Android devices that use journaling filesystems.
To make your app more efficient though, maybe you could cache data in memory, and only write out the entire file (rather than append), at certain intervals, or when you're done. If you have a lot of data, a DB might even be appropriate.

java.io.FileNotFoundException (Too many open files)

I use the following code to write some data to files:
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file));
writer.write(...);
writer.flush();
}
finally {
if (writer != null)
writer.close();
}
After invoking the method multiple times I got a FileNotFoundException because too many files are open.
Obviously java does not close the file handles when I close the writer stream. Closing the FileWriter separately does not help.
Is there sth. I can do to force java to close the files?
Your code looks fine. It could be another part of your application which is leaking file handles.
You can monitor file handles using lsof on Linux or pfiles on Solaris. On Windows, you can use ProcessExplorer.
No, Java does close the file handles when you close the writer. Its actually built using Decorator pattern. Hence, it must be something else. Show the stack trace.
See this thread about writing to files, good tips there.. pay attention to the finally block in Anons reply.
BufferedWriter closes the underlying stream. Probably, this a multithreading issue. You can keep an instance of FileOutputStream and close it. Something like:
java.io.FileOutputStream out = new java.io.FileOutputStream(file);
try {
// make buffered writer, etc.
} finally {
out.close();
}

Categories

Resources