I tried the use of Path interface;
//get a path object with relative path
Path filePath = Paths.get("C:\\Test\\filename.txt");
System.out.println("The file name is: " + filePath.getFileName());
Path filePath2 = Paths.get("/home/shibu/Desktop/filename.txt");
System.out.println("The file name is: " + filePath2.getFileName());
The out put is like;
The file name is: C:\Test\filename.txt
The file name is: filename.txt
For the windows file it printed full path and for linux file it printed only file name.
Why this difference?
Simple: On Linux, the only illegal characters in a file name are / and the 0 byte. Everything else, including \, line feed and escape sequences, are valid.
That means C:\Test\filename.txt is a valid file name on Linux. The Java runtime doesn't attempt to be smart and guess that this might be a Windows path.
Note that this is different when you use /: This is a valid path delimiter on Windows when using Java. So the path a/foo.txt is a relative path both on Linux and Windows.
This means you can open files on Windows using Paths.get("/C:/Test/filename.txt");, for example.
Related
I am making an HTTP Server in Java so that (on start) it finds all files in a directory (and it's sub-directories) and adds them to the server. But when getting the path of a file and trying to give it to HttpServer.createContext(), it throws a java.lang.IllegalArgumentException: Illegal value for path or protocol. (with the string argument, say "\folder/index.html"). To get this value, I used
file.getParent().substring(24) + "/" + file.getName()
I used substring because I had to exclude the folder the web server is in. The illegal character is the backslash. I have tried extending File to change separator and separatorChar, but that only created 2 new variables. While using String.replace() didn't seem to have any effect. Is there a different method than File.getParent or File.getPath that I can use, or is there a way to use String.replace that I am not seeing?
EDIT:
String.replace() seems to be the best answer... But I am not completely sure how to use it.
EDIT 2: For some reason the backslash isn't showing up, so I changed it.
You have to use the java System.getProperty.
Notice that, in this context, "file.separator" is a key which we are
using to get this property from current system executing the java VM.
Insteady of using a slash (/), you should choose a platform agnostic file separator, as an example it should be:
String separator = System.getProperty("file.separator");
System.out.println(separator);
// unix / , windows \
Have a look at Paths.get(...)
Try Paths.get(".") // current working directory.
Or tell it, on which path it should start:
Use System.getProperty("user.dir"), for current loged in user, home directory.
String pathStr = "/";
Path homeDir = Paths.get(System.getProperty("user.dir"))
Getting from the user directory into the data directory: homeDir.get("data")
Path dataPath = Paths.get(System.getProperty("user.dir"));
File dataFile = dataPath.toFile();
Now use operations on dataFile, to check what files and directories there are, on that location of the file system.
I do not own a Windows copy, but would like to know the behavior and recommended usage in Java for representing a path such as \autoexec.bat under Windows?
Semantically, such a path would represent the file autoexec.bat on the root of any file system. Thus it would need to be resolved against a path representing a disk drive (such as C:\) before representing a file. In that sense, it is not absolute. However, it also does not have a root component, I suppose.
Can such path be created when running the JVM on Windows? If so, what would getRoot() and isAbsolute() return?
I tried the following code using Memory File System, but this throws InvalidPathException: “path must not start with separator at index 1: \truc”. Does this faithfully reflect the behavior under Windows, or is it a quirk of this specific library?
try (FileSystem fs = MemoryFileSystemBuilder.newWindows().build()) {
final Path truc = fs.getPath("\\truc");
LOGGER.info("Root: {}.", truc.getRoot());
LOGGER.info("Abs: {}.", truc.isAbsolute());
LOGGER.info("Abs: {}.", truc.toAbsolutePath());
}
Such paths are valid in the Windows terminal, or at least they were last time I used Windows (a long time ago). It would be handy to create such path in order to mark that the path is “absolute” (in the sense of starting with a backslash, thus not relative to a folder), but still leave the path without a driver letter specified. Then such a path can be (later) resolved to C:\autoexec.bat or D:\autoexec.bat or …
In Windows, \\ refers to the current drive which is C:\ in my case.
Not sure how the MemoryFileSystemBuilder works but the following code
File file = new File("\\test.txt");
final Path truc = file.toPath();
System.out.println("Root: " + truc.getRoot().toString());
System.out.println("Abs: " + truc.isAbsolute());
System.out.println("Abs: " + truc.toAbsolutePath().toString());
gives the below output
Root: \
Abs: false
Abs: C:\test.txt
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());
I am having trouble accessing a file within my Jar on Windows. I do not have this problem when I run it on Unix. I have created the jar both on Windows & Unix and it makes no difference. Either way it does not run on Windows.
I ran the jar -tf command on my jar and the class I am running from is located in: a/b/c/d/ClassOne.class. The class I am looking for is located in my base directory of the jar: ClassTwo.class
My code in this ClassOne looks like the following:
String path = File.separator + "myYAML.yml";
InputStream in = MetricCollector.class.getResourceAsStream(path);
InputStreamReader isr = new InputStreamReader(in);
BufferedReader input = new BufferedReader(isr);
My code breaks on the last line shown throwing a NullPointerException which I can only believe means it cannot find the path I have given it. However, this exact code works great on my debugger and on Unix when I run the jar.
I have also tested the following paths:
"myYAML.yml"
File.seperator + ".." + File.seperator + ".." + File.seperator + ".." + File.seperator + ".." + "myYAML.yml"
".." + File.seperator + ".." + File.seperator + ".." + File.seperator + ".." + "myYAML.yml"
all to no avail.
I have used the following Stack Overflow posts to get as far as I can, but they do not seem to have an answer for me: How to reference a resource file correctly for JAR and Debugging?, Accessing resources within a JAR file and Reading file from within JAR not working on windows
Any additional help I would be extremely grateful for. Thanks in advance.
File.separator cannot work on Windows, it returns \. You need to use / as a separator regardless of the OS.
The Class#getResource(String) states
Before delegation, an absolute resource name is constructed from the
given resource name using this algorithm:
If the name begins with a '/' ('\u002f'), then the absolute name of
the resource is the portion of the name following the '/'. Otherwise,
the absolute name is of the following form: modified_package_name/name
Where the modified_package_name is the package name of this object
with '/' substituted for '.' ('\u002e').
In other words, you must use /. This is further explained in the javadoc for ClassLoader.html#getResource(java.lang.String) to which Class#getResource delegates.
The name of a resource is a /-separated path name that identifies the
resource.
If the resource is at the root of the classpath, use
InputStream in = MetricCollector.class.getResourceAsStream("/myYAML.yml");
I'm trying to list a directory's contents, and rename certain files.
public void run(String dirName) {
try {
File parDir = new File(dirName);
File[] dirContents = parDir.listFiles();
// Rename if necessary
for(File f : dirContents) {
System.out.println("f is:\n" + f.toString());
String name = f.getName();
String subbedName = name.replaceAll("\uFFFD", "_");
System.out.println("\n" + "name = " + name + ", subbedName = " + subbedName + "\n");
if(!name.equals(subbedName)) {
File newFile = new File(f.getParentFile(), subbedName);
System.out.println("newFile is:\n" + newFile.toString());
if(!f.renameTo(newFile))
System.out.println("Tried to change file name but couldn't.");
}
}
}
catch(Exception exc1) {
System.out.println("Something happened while listing and renaming directory contents: " + exc1.getMessage());
}
}
When I run this, I get "Tried to change file name but couldn't." I don't believe that Java is considering these files to be "open", so I don't think that's the reason. I've even ran chmod 777 myDir where myDir is the value of the dirName string passed into the run method.
What am I missing here? Why won't Java rename these file(s)? These are CentOS machines.
Edit: Added printouts for both f and newFile, which is as follows:
f is:
/root/path/to/mydir/test�.txt
newFile is:
/root/path/to/mydir/test_.txt
You need to create your new File object with the full pathname of those files. So
String name = f.getName(); // gets the name without the directory
should likely be:
String name = f.getAbsolutePath();
(your search/replace may need to change)
The problem is that f.getName() returns the last name component of the path that is represented by f. You then massage this String and turn it back into a File. But the File now represents a path relative to the current directory, not the directory containing the original path.
As a result your code is actually attempting to rename the files from dirName into the application's current directory. That could fail because files already exist in the current directory with those names, or because the dirName and the current directory are in different file systems. (You cannot rename a file from one filesystem to another ... you have to copy it.)
Please note that a File in Java represents a pathname, not a file or a folder. In your code, the f objects are the pathnames for file system objects (either files or folders) in the directory denoted by the String dirname. Each of these f objects will have a directory part.
There is more than one way to fix your code; for example
change name = f.getName() to name = f.toString()
change new File(subbedName) to new File(f.getParentFile(), subbedName)
I have an alternative / additional theory.
The pathname of the file containing the \uFFFD character is coming out as "mojibake"; i.e. the kind of garbled text that you get when you display encoded text using the wrong encoding. And since we are seeing 3 characters of garbled text, I suspect that it is attempting to display the UTF-8 rendering of \uFFFD as Latin-1.
So my theory is that the same think is happening when the File.renameTo method is converting f to the form that it is going to provide to the system call. For some reason that is no clear to me, Java could be using the wrong encoding, and as a result producing a "name" for the original file that doesn't match the name of the file in the file system. That would be sufficient to cause the rename to fail.
Possibly related questions / links:
File name charset problem in java
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4733494 (Note that Sun decided this was not a Java bug, and most of the "me too" comments on the bug report are from people who do not understand the explanation ...)
f.getName(); only returns the name of the folder, not the full path. So subbedName becomes a relative path file. Try something with f.getCanonicalPath() instead.