I'm developing a Java software that reads lots of possibly big files.
I'll try to parallelize it, so it reads in parallel files from different devices (HDD, SSD, flash drive, SMB, etc) and only 1 file at a time from each device. But for that I'd need to know in which device a given file is.
On Windows I guess I could just use substring its path for the drive letter, but for Linux I have no idea how that could be done. Is there a standardized way to do it?
The sun.nio.fs.UnixFileAttributes class, which is used for PosixFileAttributes, contains a st_dev field. Unfortunately, it is not public accessible, you might have to use reflection to get the value.
A different approach would be to call stat on the file and read the device id that way. Then you can use the device id to find out which device the file is on.
Also you might want to check the output of mount to check the paths you are using and where they are mounted on.
Related
I'm still searching, but maybe anyone faced with the same issue.
I'm maintaining an app. This app stores some data in two places (lets say on sdcard/example and external_memory/example). Before the migration to the newest Android Api everything worked fine using ExternalStorage.getAllExternalStoragePaths(). Now I'm still able to get both paths, but the sdcard/example path is not readable and not writable..
I read about the SAF, but in my case that is not a solution - the files stored in both directories are parsed using a native library (C++) - I need path to it like /storage/sdcard/example/test.xml. Otherwise the library is not able to read this file. Unfortunately I cannot change the library because of missing sources.
I would like to ask three questions:
Is there any other way to ask access to directory on SD Card and use this directory like the old way?
Maybe I can say Android - "hey, I want have Example directory on SD Card and maintain it"?
Or maybe I can use SAF without ContentResolver?
Moving files to /storage/sdcard/Android/data/com.example/files/ is not acceptable by stakeholders.
Is there any other way to ask access to directory on SD Card and use this directory like the old way?
No, short of building a custom ROM or rooting the device.
Maybe I can say Android - "hey, I want have Example directory on SD Card and maintain it"?
No. The closest thing is getExternalFilesDirs(), getExternalCacheDirs(), and getExternalMediaDirs(). If those return 2+ items, the second and subsequent ones will be on removable media, and you can read and write to those paths. However, you do not control what the paths are.
Or maybe I can use SAF without ContentResolver?
No, insofar as you cannot get a filesystem path.
Here the problem: my app will generate some files, and I want to give to the users the opportunity to exchange these files between them.
This requires 3 steps:
Saving the data: easily done in Storage implementing the
functions required by the Externalizable class;
Sharing the data: done (probably, right now it's impossible to check if the
result is correct because the missing step 3) with the sharing
methods offered by the framework, as soon as I understood I needed
to use as mimetype "application/octect-stream";
importing the downloaded data (shared by another user): this one I can't manage to
find a way to make it work. Loading the files from the app's Storage
is easy, but accessing to the folders out of the app's Storage is
something I can't manage to do.
I used FileSystemStorage in the hope of gaining access at least to the Download folder that (mostly) every phone has, but apparently I can't manage to accomplish the task
Using the FileSystemStorage on Android, for example, I have access to
/storage/emulated/0
/storage/emulated/legacy
file:///system
The first two being related to the Storage of the app.
Acceding to file:/// I obtain a long list of folders, a partial list including
media
logs
sdcard
Removable
...
root
...
But when I try to access some of these, they all appear to be empty. Either I make some mistake or the app can't see their content.
So I wonder if there is a way to accomplish the task, namely to have access to the files (probably in the Download folder) the user has downloaded, to import them.
Phone apps live in isolation within the phone. Android literally creates a separate Linux user for every app so they don't step on each other and damage the phone. iOS does similar tricks.
As a result apps can't just write a file to downloads and can't just list all the files there. This would violate the users privacy. So the native API to share a file is usually separate from the files API. We do have a share API in the CN class which lets you share images etc. to an arbitrary OS app. See isNativeShareSupported and share.
Ok, maybe I found a solution for reading the files from the Download folder in an extension of CodenameOne called FileChooser.
According to this blog post it should give access to, between the others, the Download folder (at least in Android).
I'm going to try it and, when everything is ready and tested, edit this reply to say how it worked out for me.
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.
In my Android App I save some files with some data file using
FileOutputStream savedList = new FileOutputStream(Path);
in a folder named myApp located in the SD storage
Unfortunately I have noticed that some cleaner Apps, not well implemented, also very popular (e.g. CleanMaster) wrongly remove the files every time the user perform a temp\trash file cleaning causing problems.
Is there a way to protect (and unprotect for writing) the file programmatically to avoid this?
How to change file permissions?
Since aren't used the file extensions to recognize the file format, how could I change the metadata of the file that are used to determine the file format so that these file are see as documents by these apps? I suppose that the scan of these Cleaners use some strategy based on Linux file format recognition and remove all object files.
Android allows to have private directory on SD card for the app.
you can get the path for private directory for your app as follows.
File myDir = getExternalFilesDir(null);
The null parameter indicates that you are going to store any type of files in the directory
myDir.mkdirs();
Log.d("info", myDir.getPath());
These files are internal to the applications, and not typically visible to the user as media.
This is like getFilesDir() in that these files will be deleted when the application is uninstalled, however there are some important differences:
Shared storage may not always be available, since removable media can be ejected by the user. Media state can be checked using getExternalStorageState(File).
There is no security enforced with these files. For example, any application holding WRITE_EXTERNAL_STORAGE can write to these files.
This solution worked for me as cleaning apps on devices don’t clean these folders considering them as private folders for the respective apps.
Checkout following link from android docs. Context.getExternalFilesDir(java.lang.String)
Write it to your private internal drive, so they don't have permission to touch it. SD cards are just FAT32 drives, so they don't support file permissions or access lists.
On 4.4 phones you may be ok, as Google basically prevents any writes to the SD card outside of a private directory. Cleaner type apps won't work on it at all, for better or worse.
First, you should read the first answer of this question. The thing to remember :
No, Environment.getExternalStorageDirectory() refers to whatever the device manufacturer considered to be "external storage". On some devices, this is removable media, like an SD card. On some devices, this is a portion of on-device flash.
The SD card is a vague notion, it's quite impossible to be 100% sure you are writting on the SD card.
That thing said, you should use the Android API to write your file on the private directory of the app, located in /path/to/external/storage/whatever/it/is/on/the/device/Android/data/com.package.yourapp/files
Use getExternalFilesDir to get the above File and write your file on the private directory of your app, this way, no one will be able to delete it.
I want to lock files that is on the sdcard of android.
I need to lock them so no one except my software can delete copy move or send them over bluetooth or any other way.
How can I do it?
There is no way to lock a file in Android; even if there was, the files would only be locked when your application was running which wouldn't stop other apps accessing the file when the user hadn't started your app.
SD Cards are usually formatted with FAT (or FAT32) and this is the case with Android. FAT offers very limited file permissions so you can't restrict access to the files this way. Again, even if you could do something like this, this wouldn't offer any protection if the user took the SD Card out of their phone and put it their PC.
If you want to keep your application's files private you need to put them in the phone's internal storage in the area reserved for you application. Each application runs with a different User ID and each application's data directory is protected using UNIX-style file permissions which prevents other applications from reading them. So while this will stop other applications having access to your files it wouldn't stop a reasonably determined user with root access to their phone copying them off.
Have a look at the Context.openFileInput(), Content.openFileOutput() and Context.getFilesDir() methods for details on how to store files in the phone's internal storage.
You cannot do this on any platform (let alone Android) using a regular SD card. Sorry!
I think you want to encrypt the file. While the file can still be moved around, it will be useless to anything but your application. People will be able to copy, move, delete but the contents won't be compromised.