I need to move a file from one directory to another in the android filesystem. How can I programmatically check if the two paths is on the same mountpoint?
The reason I want to know this is because if they are, we need to copy the bits instead of using File.rename(newPath).
Examples when the paths is on different mountpoints:
The user wants to move a file from the internal to external storage.
The user wants to move a file from /sdcard/files to /sdcard/external_sd/files on a samsungdevice.
Call File.rename. If it succeeds, they're on the same mountpoint.
One way to determine which filesystem a file resides on from within an Android app:
get the file's canonical path by calling File.getCanonicalPath() on it.
then get the list of currently mounted filesystems & their mount point paths from /proc/mounts
and find which mount point path is the most complete string match for the canonical path of the file in question, this should give you the mount point / filesystem of the file.
Compare results from the two files.
Related
Linux Api has O_TMPFILE flag to be specified with open system call creating unnamed temporary file which cannot be opened by any path. So we can use this to write data to the file "atmoically" and the linkat the given file to the real path. According to the open man page it can be implemented as simple as
char path[1000];
int fd = open("/tmp", O_TMPFILE | O_WRONLY, S_IWUSR);
write(fd, "123456", sizeof("123456"));
sprintf(path, "/proc/self/fd/%d", fd);
linkat(AT_FDCWD, path, AT_FDCWD, "/tmp/1111111", AT_SYMLINK_FOLLOW);
Is there a Java alternative (probably non crossplatform) to do atomic write to a file without writing Linux-specific JNI function? Files.createTempFile does completely different thing.
By atomic write I mean that either it cannot be opened and be read from or it contains all the data required to be writted.
I don't believe Java has an API for this, and it seems to depend on both the OS and filesystem having support, so JNI might be the only way, and even then only on Linux.
I did a quick search for what Cygwin does, seems to be a bit of a hack just to make software work, creating a file with a random name then excluding it only from their own directory listing.
I believe the closest you can get in plain Java is to create a file in some other location (kinda like a /proc/self/fd/... equivalent), and then when you are done writing it, either move it or symbolic link it from the final location. To move the file, you want it on the same filesystem partition so the file contents don't actually need to be copied. Programs watching for the file in say /tmp/ wouldn't see it until the move or sym link creation.
You could possibly play around with user accounts and filesystem permissions to ensure that no other (non SYSTEM/root) program can see the file initially even if they tried to look wherever you hid it.
As in the title, is there a standard path where to store images on an operating system?
For example, in Java you can get the "temporary folder" using System.getProperty("java.io.tmpdir"), is there a similar way to get a path for images?
If not, is there at least a path for generic data storage?
I'm writing a program that generates .pngs that have to be stored, but I want a standard path where to store them until the user chooses his own folder in the settings menu;
Thanks for your time.
I'm not aware of a OS independent path for storing images. Especially with all the unix distributions this might vary from case to case. It also might change based on the localization of the OS. The best way I'd say would be to ask the user where to store the images OR get the users home directory and then store it in a folder called like your program so it is clear to the user where this folder comes from.
If you want to let the user choose where to save them to begin with, then I would recommend either:
Don't save anything to their system without their explicit say-so; that is, don't save anything to the disk anywhere until they select a location for it to go, or
Save it to the temporary folder until they select a specific location to store the image. This way, your code will be generically portable; where specific files live varies between people, but a temp directory is universal.
normally the current working directory is used
System.getProperty("user.dir");
or you can use a relative directory of the home directory
new File(System.getProperty("user.home"), "Pictures");
https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#getProperties()
I wish to place a file named as myFile.file in
C:/Windows/System32/ location.
Here is use java code to place my file. while I execute my program it throws "Access Denied:C:/Windows/System32/myFile.file".
why is it happening? Is it possible to place in that location?
That (and many other) system locations are restricted for admin users/elevated applications.
Application data should be stored in the user application data files in the user profile (or the common application data).
If you really must write into the system folder, then you will need to ask the user for permission via UAC, either by using ShellExecute() with the runas verb to run another program, or COM elevation (if that's possible in Java)
Update
See Andrew's answer for a method to get the correct path in Java.
Put myFile.file in a sub-directory of user.home.
The sub-directory could be the package name of the class saving the file. E.G. if your main class is our.com.Main, store the file at ${user.home}/our/com/myFile.file. The reason to use a sub-directory is to help prevent another apps. myFile.file from overwriting or interfering with your own version.
To get the location of user.home, see:
System.getProperty("user.home");
The value of user.home here, is:
Name Value
user.home C:\Users\Andrew
This technique will work reliably for Mac. & *nix, as well as Windows.
I want to save data to my Sony Ericsson K750i. I know the phone implements FileConnection version 1.0. The list of roots taken from
FileSystemRegistry.listRoots();
returns single element named "c:/". I want to save a file.txt just about anywhere, but preferably to the memory stick attached. Unfortunately, it doesn't seem to work. It throws an IOException without any message. I tried opening the fileconnection on numerous roots like c:/, C:/, /, ./, root1/, SDCard/, CFCard/, MemoryStick/ and perhaps some more but without any luck.
The exception is thrown right after this line for any of those roots:
FileConnection filecon = (FileConnection) Connector.open("file:///MemoryStick/file.txt");
Please, what URL should i use?
I would suspect that your problem is that you are trying to write a file in a location your MIDlet isn't allowed to write to.
My guess is that you can read "c:/" just enough to figure out what its subfolders are. You can't create a file or a subfolder.
However, browse through c: subfolders and there should be a location somewhere where you can create a subfolder and/or a file.
Of course, all this assumes that your MIDlet is signed with a certificate that puts it in a security domain allowing good enough file system access.
Is there a way to search an entire computer for a String value representing a file name in Java? This would be without knowing the names of the drives on the computer.
You can iterate through the file system by looking at file names, getting the contents if it's a directory, etc. recursively.
If the sticking point is how to get the drives on the computer, look at the File.listRoots() function to get a list of the drive letters.
ETA:
To be absolutely safe, you'll want to include some limits on recursive processing. It's possible to have loops in the file system with symbolic links and such (especially in LINUX/UNIX, but third party tools can enable this in Windows as well).
To make sure you don't get into a loop when dealing with symbolic links, use the File.getCanonicalPath methods to get the "real" path for the directory and keep track of all visited canonical paths. You could also use getCanonicalFile and keep track of all the files, but that's probably not needed unless you really want to avoid the occasional instance where you'll process the same file twice.
You can use the File object to determine whether you are looking at a file or a directory:
File file = new File("/"); //root
Then as you are recursing (or iterating depending on your preference) you have a simple check:
if(tempFile.isDirectory())
//do recursive call on that directory
else
//perform check on file name
Also not forget exceptions in recursive processing. Some folders may not be accessible due to access right restrictions. Also, the Windows system folder "System Volume Information" cannot be entered in Windows Explorer, so I suppose it will throw an exception if you try to get inside programmaticaly.
You can use a recursive call through the entire file system: You can use the following methods of java.io.File:
listRoots(): list the root files (In Windows it's the drives, on Mac OS X and linux it's '/').
listFiles(): list the enclosing files of a directory