I'm currently working on a JavaFX application that uses a save file to load information about the previous session. I am having problems closing my BufferedReader and BufferedWriters. Files are not being unlocked until the JavaFX application is terminated. I have traced through the code and to ensure that there are no BufferedReaders and BufferedWriters left un-closed. If I try to modify the files after JavaFX is closed, they will be renamed and deleted correctly. Here's an example of one of my methods for reading and writing to files.
This is a school assignment and external libraries are not allowed.
public static boolean addNewAccount(User user, String fileName)
{
try
{
File output = new File("temp.csv");
File input = new File(fileName);
if (output.exists())
{
output.delete();
output.createNewFile();
}
BufferedWriter outputStream = new BufferedWriter(new FileWriter(output.getName()));
BufferedReader inputStream = new BufferedReader(new FileReader(input.getName()));
...
Read and write stuff here.
...
inputStream.close();
inputStream = null;
outputStream.close();
outputStream = null;
System.gc();
input.delete();
if (!output.renameTo(input))
{
HistoryLog.getInstance().log("Something is preventing a file from being closed.");
return false;
}
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
Related
I'm writing and reading from a file and it works perfectly fine. However when the activity is switched or the app is closed it appears that the file is deleted or some such as null is returned when trying to read from the file. I believed it may be because I have an onCreate blank write to the file but that should only run upon the launch to make sure the file is created. I don't mind if the file doesn't persist between launches however it should at least persist between activities.
//in oncreate is writeToHistory("");
public void writeToHistory(String toWrite) {
try {
File path = getApplicationContext().getFilesDir();
File file = new File(path, "JWCalcHistory.txt");
FileOutputStream fos = new FileOutputStream(file);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
bw.write(toWrite);
bw.close();
} catch (Exception e){
e.printStackTrace();
}
}
public void btnAnsClicked(View v) throws IOException {
File path = getApplicationContext().getFilesDir();
File file = new File(path,"JWCalcHistory.txt");
BufferedReader br = new BufferedReader(new FileReader(file));
String oldAns = br.readLine();
if (!(oldAns.equals("null") || oldAns.equals(""))) {
if (Character.isDigit(readableSum.charAt(readableSum.length() - 1))) {
oldAns = "*" + oldAns;
}
UpdateSum(oldAns);
}
}
If someone can point out a way to make the contents of the file persist always until it is programmatically deleted or cleared then please let me know. The file doesn't already exist and is created upon the code being run.
You need to check if the file exists first. Something like this:
public void writeToHistory(String toWrite) {
try {
File path = getApplicationContext().getFilesDir();
File file = new File(path, "JWCalcHistory.txt");
if(file.exists()) return;
FileOutputStream fos = new FileOutputStream(file);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
bw.write(toWrite);
bw.close();
} catch (Exception e){
e.printStackTrace();
}
}
I'm using this within an application where writing to a file is not possible. The data is always in streams. I get the XLSX file in an inputstream and I would like to set a password and write it to an outputstream.
public void encrptXslxFile(InputStream inStream, OutputStream outStream){
POIFSFileSystem fs = null;
EncryptionInfo info = null;
OutputStream fos;
OPCPackage opc = null;
try {
info = new EncryptionInfo(EncryptionMode.agile);
Encryptor enc = info.getEncryptor();
enc.confirmPassword("coffee");
//inStream = new FileInputStream("C:\\ProjectWork\\Community\\excelfile.xlsx");
fs = new POIFSFileSystem();
opc = OPCPackage.open(inStream); //from parameter
OutputStream os = enc.getDataStream(fs);
opc.save(os);
os.close();
//fos = new FileOutputStream("C:\\ProjectWork\\Community\\excelfilepwd.xlsx");
//fs.writeFilesystem(fos);
//fos.close();
fs.writeFilesystem(outStream); // from parameter
outStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
While reading from the file and writing to the file, it encrypts fine. But if I use the function and then get the outputstream, and later write it, it creates a zero kb file.
Is this even possible?
I tested with the code below to makes sure the inputstream is good.
public void encrptXslxFile(InputStream inStream, OutputStream outStream){
try {
IOUtils.copy(inStream, outStream);
} catch (IOException e) {
e.printStackTrace();
}
}
I was able to write the outputstream to a file.
Since I cannot create files and POI internally uses files, I had to specifically set the temp directory for POI to use.
TempFile.setTempFileCreationStrategy(new TempFileCreationStrategy() {
#Override
public File createTempFile(String prefix, String suffix) throws IOException {
// check dir exists, make if doesn't
if(!fileTempDir.exists()){
fileTempDir.mkdir();
fileTempDir.deleteOnExit();
}
File newFile = File.createTempFile(prefix, suffix, fileTempDir);
return newFile;
}
#Override
public File createTempDirectory(String strPath) throws IOException {
if(!fileTempDir.exists()){
fileTempDir.mkdir();
fileTempDir.deleteOnExit();
return fileTempDir;
}else {
return Files.createTempDirectory(strPath).toFile();
}
}
});
This worked for me.
I'm writing a logger to my java program (in csv format) with bufferedWriter and FileWriter.
When i open the csv file while the program is running and continues writing to the file, I got this exception: "The process cannot access the file because it is being used by another process".
What i want is when i open the csv file while the program is running, The csv file will open in read mode and the program will writing successfully to the file.
I solved it by changing the closing of bufferedWriter and FileWriter to .flush() instead of .close()
Original minimal logger code (with the original close function)
public class logger {
private BufferedWriter bw = null;
private FileWriter fw = null;
private File file = null;
logger(String nclass) {
path = "c:\\test\\test.csv";
this.file = new File(path);
// Check if the file is already exist.
if (!file.exists()) {
file.createNewFile();
}
fw = new FileWriter(file.getAbsoluteFile(), true);
bw = new BufferedWriter(fw);
}
public void writeToFile(String msg) {
entryWrite();
try {
fw = new FileWriter(file.getAbsoluteFile(), true);
bw = new BufferedWriter(fw);
fw.append(msg);
} catch (IOException e) {
e.printStackTrace();
} finally {
close();
exitWrite();
}
}
}
private void close() {
try {
if (bw != null) {
bw.close();
bw = null;
}
if (fw != null) {
fw.close();
fw = null;
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
My solution function
private void close() {
try {
if (bw != null) {
bw.flush();
bw = null;
}
if (fw != null) {
fw.flush();
fw = null;
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Now my answer is if it is ok not to close the stream and just use with flush?
Can there be any problems later? Because in all my tests its run well.
Thanks !!
Would it be ok some honesty?, in a very humble way. Sorry but stinky code:
why setting to null "bw" and "fw"?, globals?, why?
"ex.printStackTrace();" ? really?, no log4j or alike?
why not using a finally block?, what happens if an exception occurs while reading writing the file?
Someone has already answered this, for code refer to this excellent answer:
Is it necessary to close a FileWriter, provided it is written through a BufferedWriter?
Just do bufferedWriter object close.
bw.close();
say, you have a large file.txt.
Now u are gonna take something from a file and make a new smaller text file each time.
in that case,
somehow you have to write some lines of code to determine when you finish writing on a particular file. Then use flag to write bw.close();
eventually, you have to initialize the second file and do your task. then bw.close();
if you don't write fw.close(), then the file will be empty.
so, make sure each file writing operation you have to write bw.close()
I have a custom java server. It uses an external xml config file.
I have some command line options to help the user, the usual stuff for showing a help file, setting ports, etc...
I've recently added a command to generate a default config file for the server. It's an xml file. After researching my options, packing a default xml file in the jar seemed to be the way to go, but I'm obviously missing something.
So far my code looks like this:
public class ResourceLoader {
private File outFile = null;
private Reader fileReader = null;
private Writer fileWriter = null;
private InputStream is = null;
private char[] buffer = null;
public ResourceLoader() {
outFile = new File("default-server.xml");
}
public void generateDefaultServerXml() {
is = ResourceLoader.class.getResourceAsStream("/default-server.xml");
if (is == null) {
System.out.println("Configuraiton File generation failed. The InputStream is null.");
} else {
fileReader = new InputStreamReader(is);
}
buffer = new char[4096];
FileOutputStream fos;
try {
fos = new FileOutputStream(outFile);
fileWriter = new OutputStreamWriter(fos);
while (fileReader.read(buffer) != -1) {
fileWriter.write(buffer, 0, buffer.length);
fileWriter.flush();
buffer = new char[4096];
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
fileReader.close();
fileWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The code above works perfectly fine when I run it in eclipse, but intitially, after I export the jar file the server could not locate the default-server.xml file when I run the command from the terminal.
The file itself is located in a package called main.resources along with some other config files and the above class.
I have since moved the ResourceLoader.class to another package. After doing that the server seems to find the xml file in the main.resources package (InputStream is not null) but the resulting generated default-server.xml file is empty.
Again, this all works perfectly well when I run it in eclipse, it's only after I export the project and try issue the command from the terminal that the process fails. What am I doing wrong?
The above class is instantiated, and the generateDefaultServerXml() is called, from the main method of the server.
EDIT: My path for writing default-server.xml was slightly wrong. Now that I've adjusted it the code works exactly as expected when I run it in Eclipse. The resource is read in the correct way, and written to the file in the correct location. But it still doesn't work when I try the same thing from the jar file.
You current line ResourceLoader.class.getResourceAsStream("/default-server.xml") means that you are trying to load a resource named default-server.xml from the root of your classpath, or put simpler, from the root of your jar file. This means that xml file should NOT be in any package inside the jar file.
When you assemble your jar file and then run jar tf my.jar on it, do you see your default-server.xml file? Does it reside in some package or in the root of the jar file?
The problem here is since you are packaging the application as a jar. The procedure to call an external resource is quite different.
You need to have a folder structure as
root
--your jar
--your xml file
Your code shallwork if the application is using an default-server.xml file inside the jar.
Otherwise, Replace below line in your code if you want to use an external default xml file.
is = new FileInputStream("./default-server.xml");
If the output file you want at root location the use below code
public ResourceLoader() {
outFile = new File("./default-server.xml");
}
Alternate code as per discussion
public class ResourceLoader {
public void generateDefaultServerXml() {
try {
String defaultxmltext =readFileToString("/default-server.xml");
writeFileFromInputString(defaultxmltext);
} catch (IOException e) {
//exception
}
}
public static void writeFileFromInputString(String everything) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter("./default-server.xml"))) {
everything = everything.replaceAll("\n", System.getProperty("line.separator"));
writer.write(everything);
}
}
public static String readFileToString(String path) throws IOException {
String everything = null;
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
everything = sb.toString();
}
return everything;
}
}
Hope this helps
consider your file located on src/main/resources try this
getClass().getClassLoader().getResource(fileName)
well as far as i can see your main problem is that you are passing the wrong path, since you mentioned the xml is under main.resources you will need to add this to the path when trying to load the file, here is a sample piece of code that should work for you
Scanner sc = null;
PrintWriter writer = null;
try {
sc = new Scanner(getClass().getResourceAsStream("main/resources/server.xml"));
writer = new PrintWriter("./default_server.xml", "UTF-8");
while(sc.hasNextLine()) {
writer.println(sc.nextLine());
}
} catch (Exception e) {
} finally {
if(sc != null) {
sc.close();
}
if(writer != null){
writer.close();
}
}
So here is the situation:
I have a .xslm file (a macro enabled excel worksheet) on server. There are no issues in opening this file on server (using ms-excel 2013).
I then edit the file using Apache POI 3.13. Save a copy of this file on server and give the other to the user for download.
(This is done just to check if we have any write issues while editing. The original purpose was just to give it as download)
The copy of this file saved on server is opened without any issues. But the one sent as download throws this error while opening it from excel 2013.
I am using Jquery.fileDownload() on the client side to make the ajax call to the server where I have my Spring Controller serving the file.
Here is my code to write the file:
Workbook workbook = null;
ServletOutputStream out = null;
InputStream inputStream = null;
FileOutputStream fos = null;
try {
OPCPackage inputFilePackage = OPCPackage.open(<original file saved on server>);
workbook = WorkbookFactory.create(inputFilePackage);
//Do Some stuff to edit workbook here
fos = new FileOutputStream("temp.xlsm");
workbook.write(fos);
fos.close();
inputStream = new FileInputStream("temp.xlsm"); // The file that is created just now
servletResponse.setContentType("application/vnd.ms-excel.sheet.macroEnabled.12");
servletResponse.setHeader("content-disposition", "attachment; filename=NewFile.xlsm");
servletResponse.setHeader("Set-Cookie", "fileDownload=true; path=/");
out = servletResponse.getOutputStream();
// workbook.write(out); // Was previously using this method to directly write to ServletOutputStream
int i;
while ((i = inputStream.read()) != -1) {
out.write(i);
}
out.flush();
// new File("temp.xlsm").delete();
}
catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
finally {
if (out != null) {
try {
out.close();
}
catch (Exception ex) {
LOGGER.error(ex.getMessage());
}
}
if (inputStream != null) {
try {
inputStream.close();
}
catch (Exception ex) {
LOGGER.error(ex.getMessage());
}
}
}
return "success";
Also I can clearly see the difference between the size of both the files.
The file which is opening without issues is (436,129 bytes) while the file throwing the error is (436,136 bytes). I am not sure from where these extra bytes are coming.
Any help would be greatly appreciated.