I have created a simple java program that in a nutshell takes two directories and then moves one to another. The program works fine unless I try to move files across different drives, then in causes java.nio.file.DirectoryNotEmptyException even though it doesn't mind non-empty directories otherwise (in fact I need it to move everything inside of it).
try {
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e1) {
System.out.println("Something went wrong");
e1.printStackTrace();
}
Files.move(file, cgbaFile.getParent(), StandardCopyOption.REPLACE_EXISTING);
For the target, you're providing the directory you want to move the file into. This is incorrect. The target should be the new pathname that you want the file to have--the new directory plus the filename.
For example, suppose you wanted to move /tmp/foo.txt to the /var/tmp directory. You're calling Files.move("/tmp/foo.txt", "/var/tmp") when you should be calling Files.move("/tmp/foo.txt", "/var/tmp/foo.txt").
You're getting that specific error because the JVM is trying to delete the target directory in order to replace it with the file.
One of these ought to generate the correct target path:
Path target = cgbaFile.resolveSibling(file.getFileName());
Path target = cgbaFile.getParent().resolve(file.getFileName());
Related
private void copyFile() throws IOException {
Path destination;
String currentWorkingDir = System.getProperty("user.dir");
File fileToCopy = component.getArchiveServerFile();
if (path.contains(File.separator)) {
destination = Paths.get(path);
} else {
destination = Paths.get(currentWorkingDir + File.separator + path);
}
if (!Files.exists(destination)) {
try {
Files.createDirectories(destination);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
FileUtils.copyFileToDirectory(fileToCopy, new File(destination.toString()));
}
}
Basically what I'm trying to do here is copying a file in some location using the path provided in the class's constructor. The logic is like this:
If the path has file separator, I consider it a full path and copy the file at the end.
If the path doesn't have file separator, I copy the file in the working directory from which the .exe file was launched.
So far, only the first option works (the full path). For some reason, the working directory option is not working and I can't figure out why.
UPDATE: If I just change the following line:
String currentWorkingDir = System.getProperty("user.dir");
to
String currentWorkingDir = System.getProperty("user.home");
It works. So I'm guessing the problem is coming from user.dir? Maybe at runtime, the folder is already being used and as a result, it can't copy the file into it?
The weird thing is, I don't have any exceptions or error, but nothing happens as well.
UPDATE 2: I think the problem here is that I'm trying to copy a file which is embedded in the application (.exe file) that I'm executing during runtime, and java can't copy it while the current working directory is being used by the application.
UPDATE 3:
Since this copy method is used in an external library, I had to come up with another way (other than logs) to see the content of system property user.dir. So I wrote I little program to create a file and write in it the value return by the property.
To my surprise, the path is not where my application was launched. It was in:
C:\Users\jj\AppData\Local\Temp\2\e4j1263.tmp_dir1602852411
Which is weird because I launched the program from :
C:\Users\jj\workspace\installer\product\target\
Any idea why I'm getting this unexpected value for user.dir?
I got a problem when i want to update my (lets say orderNumber) and i try to renaming the file of image. lets say the original file ini MainImage15 i want to rename to MainImage16 with Files.Copy or Files.Move and after that i try to delete after succesful copying. and i got the error like this
java.nio.file.FileSystemException: C:\Users\User\apache\webapps\Promotion\030000\MainImage15.jpg: The process cannot access the file because it is being used by another process.
public void renameFileToFileSystem(final String fileName, final String oldFileLocation, final String newFileLocation) {
Path source = Paths.get(oldFileLocation);
Path destination = Paths.get(newFileLocation);
try {
Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
Files.delete(source);
} catch (final IOException ioException) {
throw new ContentManagementException(fileName, ioException.getMessage());
}
}
i dont knwo what to do. should i use buffer close? but i just renaming the file . thankyou.
I don't think Files.copy keeps the file handle open.
To make sure its true - remove the line Files.copy and rerun - the chances are that you still won't be able to delete the file.
So you must find who keeps the handle busy. There are basically two possibilities:
Its somewhere else in your code
Its some kind of external process (antivirus, another application that you've used to render the image and so forth). You can use Process Explorer that will help to find the process that keeps the handle.
I just did a little project in java, packed the .jar and application.properties to my VPS and wanted to test it there. The tool reads logfiles.
I specified the path to the logfile within the application.properties as follows:
LOGPATH=/folder1/folder2/logs/thelogIwant.log
The path is parsed as follows:
public String makePath(String path) {
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream("application.properties");
prop.load(input);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return prop.getProperty(path);
}
Path logFile = Paths.get(makePath("LOGPATH"));
It even seems to to this right, as the ErrorMessage states:
SEVERE: /folder1/folder2/logs/thelogIwant.log (No such file or directory)
The logfile is being created by another application and therefore in another directory than the .jar I am running.
The path exists on my VPS and I can navigate to and through it.
Can someone point me in the right direction? What's going wrong here?
Things I tried:
Specify path with "~/folder1/..."
Specify path with "folder1/..."
I can think of a few possible explanations:
The pathname in your config file is wrong; e.g. there is a typo or some other discrepancy that you didn't notice.
You are loading a different property file to the one that you think.
There is a mismatch between the property name in the file and the name that your tool uses.
The other application didn't create the log file
Permissions: your tool may be running as a user that isn't permitted to read one of the directories on the path.
SELinux in enforcing mode can prevent an application (e.g. running as a service) from accessing files.
Homoglyphs, either in the property file1, your source code or the name of the file in the file system.
The things that you tried are unlikely to work. A correct absolute pathname is more robust than a relative pathname, and Paths.get doesn't know how to deal with ~. (The expansion of ~ is a shell feature ....)
I would try this:
Modify your tool to output the value of the "LOGPATH" property ... enclosed in quote characters so that you can see any spurious whitespace characters at the beginning / end of the value.
Run the tool.
Using copy-and-paste, see if you can open the file using exactly the pathname that your tool uses.
In short, verify that the pathname you are actually using is what you expect it to be.
1 - In practice, classic format property files are encoded in LATIN-1, so this is impossible.
I was able to fix this, thanks #Steven for your help!
I used the pwd command when in the directory the files are in and recognized that the true absolute path starts with /home/myusername/folder1/...
Works fine now.
I've been using Java 7's ZipFS support.
https://gist.github.com/stain/5591420
shows the behaviour, which I find a bit odd. Basically you can create a ZIP file system, make a file with a given name, and then also make a folder with the same name.
The reason for this seems to be that internally the folder gets "/" appended to its name - however this new name is not returned, therefore you end up in a strange situation where Files.isDirectory() returns false immediately after a successful Files.createDirectory().
try (FileSystem fs = tempZipFS()) {
Path folder = fs.getPath("folder");
Files.createFile(folder);
assertTrue(Files.isRegularFile(folder));
assertFalse(Files.isDirectory(folder));
// try {
Files.createDirectory(folder);
// } catch (FileAlreadyExistsException ex) {
// Is not thrown!
// }
// but a second createDirectory() fails correctly
try {
Files.createDirectory(folder);
} catch (FileAlreadyExistsException ex) {
}
// Look, it's both a file and folder!
Path child = folder.resolve("child");
Files.createFile(child);
// Can this be tested?
assertTrue(Files.isRegularFile(folder));
// Yes, if you include the final /
assertTrue(Files.isDirectory(fs.getPath("folder/")));
// But not the parent
// assertTrue(Files.isDirectory(child.getParent()));
// Or the original Path
// assertTrue(Files.isDirectory(folder));
}
So as long as you have the "/" as the suffix, you can even work with both, and that's how they are listed if you do a directory listing of the root.
Now the ZIP format itself allows this as it only deals with entries in a ZIP file (even allowing multiple entries with the same name), however normal use of a "FileSystem" would normally not allow multiple entries with the same name ; as can be seen when I try to create the folder twice.
The produced ZIP file can be browsed correctly with infozip, 7Zip and Windows 8; but trying to unzip will obviously fail because the native file system don't support such duality.
So is this a feature, bug or something in between?
FileWriter outFile = null;
try {
outFile = new FileWriter("member.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.println("test");
Running that command, where is the member.txt ? I am using windows vista. UAC enabled so when I run it, I don't think it's writing to the txt file. txt file is created however, but it's empty.
Relative paths in Java IO are relative to current working directory. In Eclipse, that's usually the project root. You're also writing to out instead of outFile. Here's a minor rewrite:
File file = new File("member.txt");
FileWriter writer = null;
try {
writer = new FileWriter(file);
writer.write("test");
} catch (IOException e) {
e.printStackTrace(); // I'd rather declare method with throws IOException and omit this catch.
} finally {
if (writer != null) try { writer.close(); } catch (IOException ignore) {}
}
System.out.printf("File is located at %s%n", file.getAbsolutePath());
Closing is mandatory since it flushes the written data into the file and releases the file lock.
Needless to say that it's a poor practice to use relative paths in Java IO. If you can, rather make use of the classpath. ClassLoader#getResource(), getResourceAsStream() and so on.
If the file is successfully created (no exception is raised), it is in the current working directory.
For the Java class you're executing, right click on the file and go to "Run As -> Run Configurations..."
In this screen, go to the "Arguments" tab. At the bottom of the screen, look for the "Working directory" setting. This is the directory that your Java class will run from.
In your example, you're creating "member.txt" in the current directory, so it will show up in whatever location your "Working directory" is set to.
It depends on the IDE you're using also. It will usually go into the same directory that the file.java is located at. I think programs like Eclipse and Netbeans may toss it in a different directory.
If running from Eclipse, the current working directory will be your project's base directory (view your project properties to find that location on disk). You should be able to see the file in the Project Explorer by refreshing the project (click on the project and hit F5).
You can specify an alternative working directory from the Run Configurations dialog under the Arguments tab.