I am trying to set user defined attribute to a file, for example, version=1 to the file foo.txt. So that I can retrieve the version attribute later.
I see Java NIO package provide such mechanism, I followed this document. However, I am trying to run this in my Unix operating system, it says null pointer exception, also I see that the blog says it is window-specific. So How can write attributes to file in Unix?
UserDefinedFileAttributeView userDefinedFAView = Files
.getFileAttributeView(path, UserDefinedFileAttributeView.class);
List<String> attributeList = userDefinedFAView.list();
System.out.println("User Defined Attribute List Size Before Adding: "
+ attributeList.size());
// set user define attribute
String attributeName = "version";
String attributeValue = "1";
userDefinedFAView.write(attributeName,
Charset.defaultCharset().encode(attributeValue));
The entire source code is below:
https://gist.github.com/ajayramesh23/e21d6159d8271fe0a4cfaf7209f6fb74
Reference blog for the source-code:
http://javapapers.com/java/file-attributes-using-java-nio/
Please provide the best way in Java 7 or above to set the file attributes.
Also, I see that Java Doc mentioned this below note:
Note:
In Linux, you might have to enable extended attributes for
user-defined attributes to work. If you receive an
UnsupportedOperationException when trying to access the user-defined
attribute view, you need to remount the file system. The following
command remounts the root partition with extended attributes for the
ext3 file system. If this command does not work for your flavor of
Linux, consult the documentation.
$ sudo mount -o remount,user_xattr /
If you want to make the change permanent, add an entry to /etc/fstab.
So How to set user-defined attributes without doing above note.
I have a simple problem that I am quite struggling with. I have several files in a directory and I am reading them and passing processing them based on their type (extension). However, as an input, I receive a path to the file without extension so I have to identify the type myself.
example (files):
files/file1.txt
files/file1.txt
files/pic1.jpg
----------------
String path = "files/file1";
String ext = FilenameUtils.getExtension(path); // this returns null
Is there a way to identify the type of file when the extension is not included in the path?
Your best bet here is to "do it yourself" by implementing instances of FileTypeDetectors.
When you have this, you can then just use Files.probeContentType() to have a string returned which describes the file contents as a MIME type.
The JDK does provide a default implementation but it relies on file extensions, basically; if you have a PNG image named foo.txt, the default implementation will return text/plain where the file is really an image/png.
Which is of course wrong.
Final note: if all you really have is only part of the file name, then use Files.newDirectoryStream() and provide it with the appropriate DirectoryStream.Filter<Path>. Not sure yet why you only have part of it though.
Since you're only given part of the file name, you'll need to search for files that start with that prefix. Note that there could be multiple matches.
Using java.nio.file
Path prefix = Paths.get(path);
Path directory = prefix.getParent();
try (Stream<Path> stream = Files.list(directory)) {
stream.filter(p -> p.getFileName().startsWith(prefix.getFileName() + "."))
.forEach(p -> System.out.printf("Found %s%n", p));
}
Using java.io
File prefix = new File(path);
File directory = prefix.getParentFile();
List<File> matches = directory.listFiles((dir, name) ->
name.startsWith(prefix.getName() + "."));
for (File match: matches) {
System.out.printf("Found %s%n", match);
}
Files.probeContentType(Path) implements a basic MIME type inquiry you can use (or extend), the internal details of which are platform specific. You can also make a little utility method that walks a Set of extensions. A combination of the two approaches may be necessary, depending on your application.
The MIME type checker will give different results on different releases implementations of the JRE. So, always have a fail-over solution.
See: http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType%28java.nio.file.Path
[EDIT]
This actually does not answer the question posited, as this method needs a full, legal Path object to work on. If you are given just the stem name, and the extension is missing, then you neither have an extension to work with nor a valid Path name for Files to work with [and probeContentType() may, in some implementations, just use the extension anyway.]
I'm not sure how you can do this without Path that refers to a real on-disk file that the JRE can access, or by hand if you don't have an extension. If you don't have a File of some sort, you can't even open it up yourself to attempt file type "magic".
I am creating a FileSystem to browse the jar in case the access to my reosurces is frim within a jar.
Then I noticed that when creating a new FileSystem, it actually registers as the default file system when using Paths NIO class.
But Filesystems.getDefaultSystem keeps returning the hard disk regular one.
Why is this behaviour inconsistent and so transparent? How can I ask for the Filesystem that Paths is actually using when asked for a relative path as myResources/myResource.txt?
System.out.println("Default FS: "+FileSystems.getDefault().getClass().getName());
URI rscURI = Test.class.getClassLoader().getResource("folder").toURI();
try{ Paths.get(clURI).getFileSystem(); }
catch(FileSystemNotFoundException e){
System.out.println("A new Filesystem for "+clURI.getScheme()+" scheme is created.");
FileSystems.newFileSystem(clURI, Collections.emptyMap());
System.out.println("Default FS: "+FileSystems.getDefault().getClass().getName());
}
return Paths.get(rscURI)
You got the gist of it in your answer; Paths.get() with string arguments is in fact strictly equivalent to FileSystems.getDefault().getPath() with the same string arguments.
Now, as to URIs, it depends on the registered file system providers, and the default filesystem provider always has scheme file. The zip filesystem provider has scheme jar.
Now, if you specify a URI for a registered provider, the provider may, or may not, create the filesystem for you automatically.
Do note however that FileSystem implements Closeable, therefore AutoCloseable; it is therefore recommended that you get a hold of it, and get paths from it, so that you can correctly close it when you're done with it. If you don't, you may leak resources!
Ok, sorry I got it.
Paths.get(URI) and Paths.get(strPath) have different mechanics.
The first one loads unequivocally the specific FS, while the second one uses always getDefault() which seems to be always the disk regular one.
So if were using Paths.get(strPath) then behaviour would be as I was expecting, returning always a reference to disk's file system, coherent with getDefaultFilesystem(), no matter what you registered before,.
I know that using File object we can get the last modified time for a File (i.e. File.lastModified()). But, my requirement is to get the last accessed time for a File in Java. How do I get it?
You will need to use the new file I/O API (NIO2) which comes with Java 7. It has a method lastAccessTime() for reading the last access time.
Here is a usage example:
Path file = ...
BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class);
FileTime time = attrs.lastAccessTime();
For more information see Managing Metadata in the Java Tutorial.
You can't do it with plain Java, you'll need to use JNI to access the platform specific data such as this or use extensions to the core Java library like the following:
javaxt.io.File file = new javaxt.io.File("path");
file.getLastAccessTime();
Or, if you have Java 7, go with Esko's answer and use NIO.
How can I change the current working directory from within a Java program? Everything I've been able to find about the issue claims that you simply can't do it, but I can't believe that that's really the case.
I have a piece of code that opens a file using a hard-coded relative file path from the directory it's normally started in, and I just want to be able to use that code from within a different Java program without having to start it from within a particular directory. It seems like you should just be able to call System.setProperty( "user.dir", "/path/to/dir" ), but as far as I can figure out, calling that line just silently fails and does nothing.
I would understand if Java didn't allow you to do this, if it weren't for the fact that it allows you to get the current working directory, and even allows you to open files using relative file paths....
There is no reliable way to do this in pure Java. Setting the user.dir property via System.setProperty() or java -Duser.dir=... does seem to affect subsequent creations of Files, but not e.g. FileOutputStreams.
The File(String parent, String child) constructor can help if you build up your directory path separately from your file path, allowing easier swapping.
An alternative is to set up a script to run Java from a different directory, or use JNI native code as suggested below.
The relevant OpenJDK bug was closed in 2008 as "will not fix".
If you run your legacy program with ProcessBuilder, you will be able to specify its working directory.
There is a way to do this using the system property "user.dir". The key part to understand is that getAbsoluteFile() must be called (as shown below) or else relative paths will be resolved against the default "user.dir" value.
import java.io.*;
public class FileUtils
{
public static boolean setCurrentDirectory(String directory_name)
{
boolean result = false; // Boolean indicating whether directory was set
File directory; // Desired current working directory
directory = new File(directory_name).getAbsoluteFile();
if (directory.exists() || directory.mkdirs())
{
result = (System.setProperty("user.dir", directory.getAbsolutePath()) != null);
}
return result;
}
public static PrintWriter openOutputFile(String file_name)
{
PrintWriter output = null; // File to open for writing
try
{
output = new PrintWriter(new File(file_name).getAbsoluteFile());
}
catch (Exception exception) {}
return output;
}
public static void main(String[] args) throws Exception
{
FileUtils.openOutputFile("DefaultDirectoryFile.txt");
FileUtils.setCurrentDirectory("NewCurrentDirectory");
FileUtils.openOutputFile("CurrentDirectoryFile.txt");
}
}
It is possible to change the PWD, using JNA/JNI to make calls to libc. The JRuby guys have a handy java library for making POSIX calls called jnr-posix. Here's the maven info
As mentioned you can't change the CWD of the JVM but if you were to launch another process using Runtime.exec() you can use the overloaded method that lets you specify the working directory. This is not really for running your Java program in another directory but for many cases when one needs to launch another program like a Perl script for example, you can specify the working directory of that script while leaving the working dir of the JVM unchanged.
See Runtime.exec javadocs
Specifically,
public Process exec(String[] cmdarray,String[] envp, File dir) throws IOException
where dir is the working directory to run the subprocess in
If I understand correctly, a Java program starts with a copy of the current environment variables. Any changes via System.setProperty(String, String) are modifying the copy, not the original environment variables. Not that this provides a thorough reason as to why Sun chose this behavior, but perhaps it sheds a little light...
The working directory is a operating system feature (set when the process starts).
Why don't you just pass your own System property (-Dsomeprop=/my/path) and use that in your code as the parent of your File:
File f = new File ( System.getProperty("someprop"), myFilename)
The smarter/easier thing to do here is to just change your code so that instead of opening the file assuming that it exists in the current working directory (I assume you are doing something like new File("blah.txt"), just build the path to the file yourself.
Let the user pass in the base directory, read it from a config file, fall back to user.dir if the other properties can't be found, etc. But it's a whole lot easier to improve the logic in your program than it is to change how environment variables work.
I have tried to invoke
String oldDir = System.setProperty("user.dir", currdir.getAbsolutePath());
It seems to work. But
File myFile = new File("localpath.ext");
InputStream openit = new FileInputStream(myFile);
throws a FileNotFoundException though
myFile.getAbsolutePath()
shows the correct path.
I have read this. I think the problem is:
Java knows the current directory with the new setting.
But the file handling is done by the operation system. It does not know the new set current directory, unfortunately.
The solution may be:
File myFile = new File(System.getPropety("user.dir"), "localpath.ext");
It creates a file Object as absolute one with the current directory which is known by the JVM. But that code should be existing in a used class, it needs changing of reused codes.
~~~~JcHartmut
You can use
new File("relative/path").getAbsoluteFile()
after
System.setProperty("user.dir", "/some/directory")
System.setProperty("user.dir", "C:/OtherProject");
File file = new File("data/data.csv").getAbsoluteFile();
System.out.println(file.getPath());
Will print
C:\OtherProject\data\data.csv
You can change the process's actual working directory using JNI or JNA.
With JNI, you can use native functions to set the directory. The POSIX method is chdir(). On Windows, you can use SetCurrentDirectory().
With JNA, you can wrap the native functions in Java binders.
For Windows:
private static interface MyKernel32 extends Library {
public MyKernel32 INSTANCE = (MyKernel32) Native.loadLibrary("Kernel32", MyKernel32.class);
/** BOOL SetCurrentDirectory( LPCTSTR lpPathName ); */
int SetCurrentDirectoryW(char[] pathName);
}
For POSIX systems:
private interface MyCLibrary extends Library {
MyCLibrary INSTANCE = (MyCLibrary) Native.loadLibrary("c", MyCLibrary.class);
/** int chdir(const char *path); */
int chdir( String path );
}
The other possible answer to this question may depend on the reason you are opening the file. Is this a property file or a file that has some configuration related to your application?
If this is the case you may consider trying to load the file through the classpath loader, this way you can load any file Java has access to.
If you run your commands in a shell you can write something like "java -cp" and add any directories you want separated by ":" if java doesnt find something in one directory it will go try and find them in the other directories, that is what I do.
Use FileSystemView
private FileSystemView fileSystemView;
fileSystemView = FileSystemView.getFileSystemView();
currentDirectory = new File(".");
//listing currentDirectory
File[] filesAndDirs = fileSystemView.getFiles(currentDirectory, false);
fileList = new ArrayList<File>();
dirList = new ArrayList<File>();
for (File file : filesAndDirs) {
if (file.isDirectory())
dirList.add(file);
else
fileList.add(file);
}
Collections.sort(dirList);
if (!fileSystemView.isFileSystemRoot(currentDirectory))
dirList.add(0, new File(".."));
Collections.sort(fileList);
//change
currentDirectory = fileSystemView.getParentDirectory(currentDirectory);