moving File leads to file with path separator "/" in filename - java

I try to move a file from one directory to another.
I do this with
File fileToMove = new File("/Users/kai-dj/separator_problem/from/file_to_move.file");
File destDir = new File("/Users/kai-dj/separator_problem/to");
if (fileToMove.exists() && destDir.isDirectory()) {
fileToMove.renameTo(new File(destDir.getAbsolutePath()+File.pathSeparator+fileToMove.getName()));
}
I'd expect to find file_to_move.file in folder /Users/kai-dj/separator_problem/to after execution, but I get a file named to/file_to_move.file placed in the parent folder /Users/kai-dj/separator_problem. At least that's what Finder shows.
As I thought: "File names mustn't contain path separator characters, this can't be true.", I also checked what ls would output in terminal:
mac-book:separator_problem kai-dj$ ls
from to:file_to_move.file
to
OK – seems no /in file name. Very strange nontheless.
Why does Finder show it as file name containing /?
Why does Java rename the file to <dirname>:<filename> – especially even when I used File.pathSeparator, not / and certainly not :?
I also tried with Files.move – same result.
EDIT: Solved, but I'd still love to know, why Finder shows : as / ^^

As mentioned in the comment above, the correct member to use is called File.separator.
Also, you can avoid using File.separator in general, and use Paths instead:
System.out.println(Paths.get("/Users/kai-dj/separator_problem/to", fileToMove.getName()).toAbsolutePath());

Related

windows - User folder with special character -> class.getResource returns null [duplicate]

The getResourceAsStream-method returns null whenever running the executable jar in a directory which ends with a exclamation mark.
For the following example, I have a Eclipse project the following directory structure:
src\ (Source Folder)
main\ (Package)
Main.java
res\ (Source Folder)
images\
Logo.png
I'm reading the Logo.png as follows:
public static void main(String[] args) throws IOException {
try (InputStream is = Main.class.getClassLoader().getResourceAsStream("images/Logo.png")) {
Image image = ImageIO.read(is);
System.out.println(image);
}
}
See the attachment for 2 test cases. First, the executable jar is started from the directory "D:\test123!##" without any problems. Secondly, the executable jar is started from the directory "D:\test123!##!!!", with problems.
Are directories ending with an exclamation mark not supported? Is the code wrong?
Thanks in advance.
Probably because of this bug or any of the many similar bugs in the Java bug database:
http://bugs.sun.com/view_bug.do?bug_id=4523159
The reason is that "!/" in a jar URL is interpreted as the separator between the JAR file name and the path within the JAR itself. If a directory name ends with !, the "!/" character sequence at the end of the directory is incorrectly interpreted. In your case, you are actually trying to access a resource with the following URL:
jar:file:///d:/test1231##!!!/test.jar!/images/Logo.png
The bug has been open for almost 12 years and is not likely to be fixed. Actually I don't know how it can be fixed without breaking other things. The problem is the design decision to use ! as a character with a special meaning (separator) in the URL scheme for JAR files:
jar:<URL for JAR file>!/<path within the JAR file>
Since the exclamation mark is an allowed character in URLs, it may occur both in the URL to the JAR file itself, as well as in the path within the JAR file, making it impossible in some cases to find the actual "!/" separator.
A simple work around for Windows is to use "\" instead of "/" in the path. That would mean the "!/" character sequence is found after the full path. For instance:
new URL("jar:file:\\d:\\test1231##!!!\\test.jar!/images/Logo.png");
My Code:
File jar = new File(jarPath + "/" + jarName);
URL url = new URL("jar:" + jar.toURI() + "!" + dataFilePath);
InputStream stream = null;
try {
stream = url.openStream();
} catch (FileNotFoundException e) {
// Windows fix
URL urlFix = new URL("jar:" + jar.toURI().toString().replace('/', '\\')
+ "!" + dataFilePath);
stream = urlFix.openStream();
}
I use toURI() because it handles things like spaces.
Fixes:
The fix itself would be for Java to check if the file exists and if not continue to the next separator (the "!/" part of the url) until the separators are exhausted, then throw the exception. So it would see that "d:\test1231##!!" throws a java.io.FileNotFoundException and would then try "d:\test1231##!!!\test.jar" which does exist. This way it does not matter if there are "!" in the file path or in the jar's files.
Alternatively the "!/" can be switched to something else that is an illegal file name or to something specific (like "jarpath:").
Alternatively make the jar's file path use another parameter.
Note:
It may be possible to override something, swap a handler, or change the code to open the file first then look inside the jar file later but I have not looked.

In Java, what do the periods in this File location denote?

I'm looking at some sample code for creating a File in Java:
File f = new File("test/.././file.txt");
I'm confused at how this works - how can you have "test" , and then those .. and . in between like that? If I run this code in an arbitrary directory in my machine, why does it work(i.e I don't have a folder called "test" ).
this is part of some code for Path-Testing in java(getAbsolutePath() and etc)
thanks
The .. just means "up a directory level". The single . just means "current directory level". Why they are in your file path is beyond me. Your path seems to mean "go into the test folder, then go up a level (to the one you started in), stay in that level, then look for file.txt". You could do the same thing with just new File("file.txt").
File f = new File("test/.././file.txt"); //.. is used to go one hierarchy above in the directory structure and . is for current directory
suppose you have directory structure like ABC/test/file.txt
and if you are inside test then your . is path upto test
and .. is path upto ABC as .. represents parent directory and parent of "test" is "ABC"
the .. denote a parent directory; . denote this directory.
Having this as valid is another good reason why you should use getCanonicalPath() vs getAbsolutePath()
For example:
Lets say your file is under /folder1/folder2 directory
then
File f = new File("/folder1/folder2/folder3/../<your file>");
f.getCanonicalPath() ==> /folder1/folder2/<your file>
f.getAbsolutePath() ==> /folder1/folder2/folder3/../<your file>
Because the .. goes back up the directory hierarchy, so you'll be back to where you started (not in test). This is unnecessary as it's equivalent to:
File("test.txt")
And so should work regardless of which directory you run it in.
The ".." will go up one directory from the current directory. So, this code is basically the same as new File("./file.txt");
./ goes to the directory where your project is located
../ Goes back a folder lets say you have a resource directory
Res/graphics/sprites/image.png
If you do File file = new File("./graphics/sprites/);
That will point to the sprites directory
Now if you want to go back a file dir File newFile = file + "../";

How to get to a file by passing relative path in java?

I am trying to understand "How to get to file by passing relative path of a file or folder?" . Here is the example:
CODE:
public class somex {
public static void main {
String fileName = System.getProperty("user.dir"); <---This gives me path for the current working directory.
File file = new File(fileName + "../../xml_tutorial/sample.xlsx" );
System.out.println(file.getCanonicalPath()); <---This gives me path for the file that is residing in folder called "xml_tutorial".
}
}
>>>>
Here, I know the file location so i was able to pass correct relative path. And, managed to print the file path. I have deleted the "sample.xlsx" and executed the above code; With no failing it gives me the path name and it is same path as when the file exists (i.e. before deleting). How it is possible ? I am expecting EXCEPTION here. why it is not throwing exception ?
Two, I want to use regular expression for the file name, such as: "../../xml_tutorial/samp.*". But this doesn't do the job and it gives me IOException. Why it is not able to identify the file sample.xlsx ? (NOTE: this is when the file exist and one hundred precent sure there is only one file with the name "sample.xlsx")
I have deleted the "sample.xlsx" and executed the above code; With no failing it gives me the path name and it is same path as when the file exists (i.e. before deleting). How it is possible ? I am expecting EXCEPTION here. why it is not throwing exception ?
File doesn't care whether the file actually exists. It just resolves the path. There's no need for the file to exist in order to take the path
/home/tjc/a/b/c/../../file.txt
...and turn it into the canonical form
/home/tjc/a/file.txt
If you want to know whether the file on that path actually exists, you can use the exists() method.
On your second, unrelated question:
Two, I want to use regular expression for the file name, such as: "../../xml_tutorial/samp.*". But this doesn't do the job and it gives me IOException. Why it is not able to identify the file sample.xlsx ?
There's nothing in the File documentation saying that it supports wildcards. If you want to do searches, you'll want to use list(FilenameFilter) or listFiles(FilenameFilter) and a FilenameFilter implementation, or listFiles(FileFilter) and a FileFilter implementation.

How to enter a directory as an argument in Eclipse

Basically, I have a directory with some files in it. In run configurations I am trying to put the directory as an arguement like so: \(workspacename\directory. Then, the following code should create a list of all the files in that directory:
String directory = args[1];
File folder = new File(directory);
File[] allFiles = folder.listFiles();
ArrayList<File> properFiles = null;
for (File file: allFiles) {
if(file.getName().endsWith(".dat")){
properFiles.add(file);
}
}
the problem i'm facing is that for some reason allFiles is null.
I'll take a guess at what your problem might be:
If your argument is a relative path (as opposed to an absolute path, staring with "/" or "c:/" for example), keep in mind that files will be relative to the working directory of the application.
So new File(directory) will be relative to wherever the application is started. In Eclipse the default working directory is in the project. So if your project is in the top level of the workspace, it will be something like workspacename/project.
You can try printing out folder.getAbsolutePath(), folder.exists() and folder.isDirectory() to help diagnose your problem.
The javadocs say listFiles() will return null if the directory does not actually exist (among other things):
Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs.
Debug by verifying (debugger or printf) the args[1] value.
Also, it looks like you might be trying to use a substitution variable to insert the workspace location in the path. If so, again, you need to verify (via debugger or printf) that the placeholder is getting replaced properly.

Program not running from expected directory?

I am working on a web-based program, using Java. I am not sure exactly how to phrase this, but I expect the program to be running from within the c:/Resin/webapps/apps directory. However, when I reference a file in the program like this: "../files/randomfile.pdf", it cannot find that file. It works when I reference it like this: "c:/Resin/webapps/files/randomfile.pdf". How to I change the "running location"? (And what is the technical term for this?)
try {
Document iTextDoc = new Document(PageSize.LETTER, 27, 27, 35, 18);
HttpServletResponse res = (HttpServletResponse) pageContext.getResponse();
res.setContentType("application/vnd.ms-word");
res.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".rtf;");
RtfWriter2 rtfWriter = RtfWriter2.getInstance(iTextDoc, res.getOutputStream());
iTextDoc.open();
iTextDoc.add(new Paragraph ("Testing RTF Letterhead with Logo"));
// Use full classname to avoid ambiguity with java.awt.Image
com.lowagie.text.Image logoImg = com.lowagie.text.Image.getInstance("../files/someimage.jpg");
logoImg.setAlignment(Image.RIGHT | Image.TEXTWRAP);
iTextDoc.add(logoImg);
iTextDoc.add(new Paragraph ("Put other information about organization beneath logo"));
iTextDoc.close();
}
I get the following error with the resulting file: Adobe Reader could not open 'someFile.pdf' because it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded).
However, if I change the getInstance command to this:
com.lowagie.text.Image logoImg = com.lowagie.text.Image.getInstance("webapps/files/someimage.jpg");
it works. So my guess is that the working directory (thanks for the term) needs to be set somewhere. I am using Resin -- any idea where I should be setting this?
Thanks!
You are probably referring to the user.dir system property, which is read only. Relative paths use this as the root folder.
In a java program you can't change the running location.
First you should find out where your program is running. You can do this by calling
System.out.println( new File( "." ).getAbsolutePath() );
Now you can specify your paths relative to this directory.
From the java.io.File doc
By default the classes in the java.io package always resolve relative pathnames against the current user directory. This directory is named by the system property user.dir, and is typically the directory in which the Java virtual machine was invoked.
Broadly speaking, you should not rely on the current directory for locating files. Use full (absolute) paths, if possible (but without harcoding it in you application, of course). if the file is inside a webapp tree (or just inside the classpath), you might want to take a look at findResource() and related methods.

Categories

Resources