Failed to delete a just created File in Windows using Java - java

I'm using FileSystem to modify a properties file inside a zip file
public boolean processZip()
{
boolean wasModified = false;
Path zipFilePath = Paths.get(this.getZipFileName());
try (FileSystem fs = FileSystems.newFileSystem(zipFilePath, null))
{
Logger.info("Processing zip: #0",
this.getZipFileName());
Path source = fs.getPath(
"/some/path/some.properties");
// Delete old properties file.
Files.delete(source);
this.createPropertiesFile(source);
wasModified = true;
}
catch (NoSuchFileException e)
{
Logger.info("Properties file not found.");
}
catch (Exception e)
{
Logger.error("There was an error updating the properties in zip: " +
this.getZipFileName(),
e);
}
return wasModified;
}
protected void createPropertiesFile(Path dst) throws IOException
{
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(Files.newOutputStream(dst))))
{
bw.write(this.getProperties().getValues());
}
catch (Exception e)
{
Logger.error("There was an error creating the properties in zip: " +
this.getInputJarFileName(),
e);
}
}
But every now and then it fails on windows with the following stacktrace:
ERROR: There was an error updating the properties in zip: C:\Apps\Test\some.zip
java.nio.file.FileSystemException: C:\Apps\Test\some.zip: The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
at java.nio.file.Files.delete(Files.java:1126)
at com.sun.nio.zipfs.ZipFileSystem.sync(ZipFileSystem.java:1294)
at com.sun.nio.zipfs.ZipFileSystem.close(ZipFileSystem.java:277)
The thing is, that file gets copied by an earlier process (the process has ended when the zip file is modified). So I don't know what can be using that file in windows. At first I thought maybe the antivirus but it happens even with the antivirus off.
I'm not sure if there is something else that I can do to prevent this. It is not as frequent but every now and then it happens.
It has admin rights, I have tried exploding the zip, modify the file and zip it back. That only made the issue more frequent. I have tried also Apache commons FileUtils.forceDelete(file).
Is there something I'm missing?

Related

Files.delete did not delete the folder correctly

In the springboot project, after the files have been merged, they need to be deleted.
The main code for the merge method is:
// chunkFolder indicates the file storage folder path
Files.list(Paths.get(chunkFolder))
.filter(path -> path.getFileName().toString().contains(HYPHEN))
.sorted((p1, p2) -> {
String fileName1 = p1.getFileName().toString();
String fileName2 = p2.getFileName().toString();
int index1 = fileName1.indexOf(HYPHEN);
int index2 = fileName2.indexOf(HYPHEN);
return Integer.valueOf(fileName1.substring(0, index1)).compareTo(Integer.valueOf(fileName2.substring(0, index2)));
})
.forEach(path -> {
try {
Files.write(Paths.get(target), Files.readAllBytes(path), StandardOpenOption.APPEND);
} catch (IOException e) {
e.printStackTrace();
}
}
);
The delete method is:
public void deleteDirectory(Path targetPath) throws IOException {
Files.walk(targetPath).sorted(Comparator.reverseOrder()).forEach(path -> {
try {
Files.delete(path);
} catch (IOException e) {
e.printStackTrace();
}
});
}
In the windows environment test, delete the storage path after merging. However, the results show that the folder still exists, but cannot be accessed. If you stop the springboot project, the folder disappears.
This problem happens on Windows when you are not closing all the directory streams correctly. You must close all directory streams scanned in your code. The two examples you've shown can be fixed with try with resources:
try(Stream<Path> stream = Files.list( ... )) {
... your code
stream.xyz(...);
}
... plus same for Files.walk() in deleteDirectory. Check other similar calls in all code.
When this occurs the directory is in a strange state when viewed in Windows Explorer - visible but not accessible. Shutting down the VM clears up correctly and the folder disappears from Explorer.

java.nio.file.FileSystemException: C:\test.csv -> C:\test2.csv: The process cannot access the file because it is being used by another process in java

I have spring batch, here I am retrieving the files from the folder and then reading the file using OpenCV library, code is like this.
List<SendingFile> sendCloudFile = new CsvToBeanBuilder<SendingFile>(new FileReader(file.getAbsolutePath(), StandardCharsets.UTF_8))
.withType(SendingFile.class)
.build()
.parse();
After that when I try to delete the same file, then it is giving me an error. (The process cannot access the file because it is being used by another process.)
What I am missing here?
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
if (stepExecution.getExitStatus().equals(ExitStatus.FAILED)) {
service.updateErrorStatus(mailApplicationId, null, null);
}
for (Map.Entry<String, String> processedFile : processedFileList.entrySet()) {
File newFile = new File(recoveryFolder, processedFile.getKey());
try {
Files.move(Paths.get(processedFile.getValue()), Paths.get(recoveryFolder, processedFile.getKey()), REPLACE_EXISTING);
} catch (Exception ex) {
log.warn("Error in moving the file. ");
log.warn(ex.getMessage());
}
}
return stepExecution.getExitStatus();
}
This is a known issue: https://github.com/spring-projects/spring-batch/issues/1500.
The workaround is to use a different step to move the file instead of doing it in a listener.

Why isn't my properties file updated in my Web App project?

I am trying to read and write a properties file with all my server and database connections in my JSF web application project in eclipse. Am using log4j to write to console. My config.properties file is:
dbserver=localhost
dbname=mydatabase;instance=myinstance
dbuser=myuser
dbpassword=mypassword
I placed my config.properties file in webapp/WEB-INF/classes folder (this is the classpath right?). I have verified that it is reading the file correctly in this specific location because if I delete the file, it breaks.
In my managed bean, I have functions to read and write to the config.properties file.
public void getSettings() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("config.properties");
Properties properties = new Properties();
try {
properties.load(input);
this.server = properties.getProperty("dbserver");
this.db = properties.getProperty("dbname");
this.user = properties.getProperty("dbuser");
this.pass = properties.getProperty("dbpassword");
logger.info("Config file successfully loaded!");
} catch (IOException e) {
logger.error("Loading Database Settings Error with " + e);
} finally {
if (input != null) {
try {
input.close();
logger.info("Closing config file...");
} catch (IOException e) {
logger.error("Error closing config file with " + e);
}
}
}
}
public void saveSettings() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Properties props = new Properties();
OutputStream out = null;
try {
props.setProperty("dbserver", this.server);
props.setProperty("dbname", this.db);
props.setProperty("dbuser", this.user);
props.setProperty("dbpassword", this.pass);
URL url = classLoader.getResource("config.properties");
File file = null;
try {
file = new File(url.toURI().getPath());
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// File f = new File("config.properties");
out = new FileOutputStream(file);
props.store(out, "This is an optional header comment string");
logger.info("Config file successfully saved!");
} catch (IOException io) {
logger.error("Saving configuration properties failed error with : " + io.getMessage());
} finally {
if (out != null) {
try {
logger.info("Closing config file...");
out.close();
} catch (IOException e) {
logger.error("Failed closing configuration properties file error with : " + e);
}
}
}
}
I never had an issue reading from the properties file but had a hard time writing to the file. This issue seemed to have been solved by specifying
URL url = classLoader.getResource("config.properties");
Now, if I change the server name from "localhost" to "192.168.1.1", I can see that the new information persists even though I refresh the page or restart the server. HOWEVER... when I open the config.properties file, I still see
dbserver=localhost
when I am expecting to see
dbserver=192.168.1.1
The information seems to persist somewhere else even though the file still remains the same? How and where can I access the contents of my properties fie to see the changes that are being made to it?
Modifying the WAR file is a bad idea (for example, some web servers may notice the file modification an redeploy your app, there may be problems when the server explodes the war on deployment etc.)
I would suggest applying an alternative approach - some possibilities are:
Place the properties in a database table, so they can be easily modified
Use an external properties file for overriding your "Property.prop" file settings. You can pull this off for example as follows. Assume that the default property values are bundled in your WAR and the modified values are saved to some other path, which is defined using a system property - let say it's called CONFIG_LOCATION. Now after loading your properties from the bundle you read them also from this external "overrides.prop" file - this overrides your defaults from "Property.prop":
PropertiesConfiguration pc1=new PropertiesConfiguration(a);
try(
FileReader propReader = new FileReader(System.getenv().get("CONFIG_FILES") +"/overrides.prop"){ pc1.load(propReader);
}
When you need to save changes, you do that to "overrides.prop" - this will save all the properties, not only the changed ones, but that should have no negative effects.

How to check incoming file transfer status in apache commons io monitor

I have implemented a simple file listener using Apache commons io monitor.I have also implemented a selenium script that simply do is download file into the pre hard coded path folder.That is totally working fine.My listener monitoring downloaded files and collect the necessary information.According to my requirement i should be able to stop the file listener once my selenium script is finished execution.To do that i must know that the incoming file transferring status to handle it better way.because i can not stop listener middle of the file transferring.(sometimes download file can be heavy so it will take some time to download).So how can i know that incoming file status in Apache commons io monitor before stop the file listener.If any one knows please let me know.
Sample code snippet
public class SimpleTestMonitor {
// A hardcoded path to a folder you are monitoring .
public static final String FOLDER =
"/home/skywalker/Desktop/simple-test-monitor/watchdir";
public static void main(String[] args) throws Exception {
// The monitor will perform polling on the folder every 5 seconds
final long pollingInterval = 5 * 1000;
File folder = new File(FOLDER);
if (!folder.exists()) {
// Test to see if monitored folder exists
throw new RuntimeException("Directory not found: " + FOLDER);
}
FileAlterationObserver observer = new FileAlterationObserver(folder);
FileAlterationMonitor monitor =
new FileAlterationMonitor(pollingInterval);
FileAlterationListener listener = new FileAlterationListenerAdaptor() {
// Is triggered when a file is created in the monitored folder
#Override
public void onFileCreate(File file) {
try {
// "file" is the reference to the newly created file
System.out.println("File created: "
+ file.getCanonicalPath());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
// Is triggered when a file is deleted from the monitored folder
#Override
public void onFileDelete(File file) {
try {
// "file" is the reference to the removed file
System.out.println("File removed: "
+ file.getCanonicalPath());
// "file" does not exists anymore in the location
System.out.println("File still exists in location: "
+ file.exists());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
};
observer.addListener(listener);
monitor.addObserver(observer);
monitor.start();
}
}
Reference

Android/Java File.mkdirs() in external storage not working

First off, I want to specify that I do have
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
specified in my manifest, and I do check Environment.MEDIA_MOUNTED.
The really strange thing about this, in my opinion, is that it returns true, but it doesn't actually create the directories.
public static void downloadFiles(ArrayList<FileList> list) {
for (FileList file: list) {
try {
// This will be the download directory
File download = new File(downloadDirPatch.getCanonicalPath(), file.getPath());
// downloadDirPatch is defined as follows in a different class:
//
// private static String updateDir = "CognitionUpdate";
// private static File sdcard = Environment.getExternalStorageDirectory();
// final public static File downloadDir = new File(sdcard, updateDir);
// final public static File downloadDirPatch = new File(downloadDir, "patch");
// final public static File downloadDirFile = new File(downloadDir, "file");
if (DEV_MODE)
Log.i(TAG, "Download file: " + download.getCanonicalPath());
// Check if the directory already exists or not
if (!download.exists())
// The directory doesn't exist, so attempt to create it
if (download.mkdirs()) {
// Directory created successfully
Download.download(new URL(file.getUrl() + file.getPatch()), file.getPath(), file.getName(), true);
} else {
throw new ExternalStorageSetupFailedException("Download sub-directories could not be created");
}
else {
// Directory already exists
Download.download(new URL(file.getUrl() + file.getPatch()), file.getPath(), file.getName(), true);
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ie) {
ie.printStackTrace();
} catch (ExternalStorageSetupFailedException essfe) {
essfe.printStackTrace();
}
}
}
"if (download.mkdirs())" returns true, but when the app goes to actually download the file it throws a
FileNotFoundException: open failed: ENOENT (No such file or directory)
exception, and when I check for the directory afterwards on my phone, it doesn't exist.
Earlier in the program, the app sets up the parent download directory, and that all works fine using File.mkdir(), but File.mkdirs() doesn't seem to be working properly for me.
Your question does not give much detail about the FileNotFoundException. Check the path that triggers this. Forget what you think the path is, log it or run it through the debugger to see what it really is.
As per the directories not created correctly, verify (with your eyes) that the path is really what you think it is. I see you are already logging download.getCanonicalPath, do check in your logs what it really is.
Finally, is Download.download really saving stuff where you think it does? Before you call it you are preparing and verifying a directory using download, but then you are not using download when you call Download.download, so it's impossible to tell.
Btw, don't repeat yourself, you can rewrite without repeating the Download.download line:
if (!download.exists())
if (!download.mkdirs()) {
throw new ExternalStorageSetupFailedException("Download sub-directories could not be created");
}
}
Download.download(new URL(file.getUrl() + file.getPatch()), file.getPath(), file.getName(), true);

Categories

Resources