i am trying to get the correct path to the sd card that is inside my samsung s4 android device through my app but when i try the above paths:
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath();
String pathTwo = Environment.getExternalStorageDirectory().getAbsolutePath();
String path3 = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath();
It gets the private none-writable path of /storage/emulated/0 instead of the correct path of storage/sdcard1
I found the correct path via File explorer using the Android Device monitor but i do not want to hard code the path as the path can be different depending on the device.
kind regards
For all devices
String sSDpath = null;
File fileCur = null;
for( String sPathCur : Arrays.asList( "MicroSD","external_SD","sdcard1","ext_card", "external_sd", "ext_sd", "external", "extSdCard", "externalSdCard")) // external sdcard
{
fileCur = new File( "/mnt/", sPathCur);
if( fileCur.isDirectory() && fileCur.canWrite())
{
sSDpath = fileCur.getAbsolutePath();
break;
}
if( sSDpath == null) {
fileCur = new File( "/storage/", sPathCur);
if( fileCur.isDirectory() && fileCur.canWrite())
{
sSDpath = fileCur.getAbsolutePath();
break;
}
}
if( sSDpath == null) {
fileCur = new File( "/storage/emulated", sPathCur);
if( fileCur.isDirectory() && fileCur.canWrite())
{
sSDpath = fileCur.getAbsolutePath();
Log.e("path",sSpath);
break;
}
}
}
100% working, tested on multiple device.
Based on a previous answer, the path to external SD card actually varies with different device manufactures.
"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. Here, "external storage" means "the stuff accessible via USB Mass Storage mode when mounted on a host machine", at least for Android 1.x and 2.x.
But the question is about external SD. How to get a path like "/mnt/sdcard/external_sd" (it may differ from device to device)?
Android has no concept of "external SD", aside from external storage, as described above.
If a device manufacturer has elected to have external storage be on-board flash and also has an SD card, you will need to contact that manufacturer to determine whether or not you can use the SD card (not guaranteed) and what the rules are for using it, such as what path to use for it."
Based on this answer.
So, There is no absolute way to get this path via code.
As gilonm mentioned, external (removable) Sd path varies from device to device, but I wrote a method, which iterates through all the different ext paths that the different manufacturers use, and then it finds the exact match.
It returns empty String if path isn't found. If a path is found, you still need to verify whether the card is inserted or not. (By checking if sub-folders exist on that path)
Note: I used StreamSupport library inside the method, so you'll need to download the jar file and add it to libs folder of your project and that's it, it'll work!
public static String getExternalSdPath(Context context) {
List<String> listOfFoldersToSearch = Arrays.asList("/storage/", "/mnt/", "/removable/", "/data/");
final List<String> listOf2DepthFolders = Arrays.asList("sdcard0", "media_rw", "removable");
final List<String> listOfExtFolders = Arrays.asList("sdcard1", "extsdcard", "external_sd", "microsd", "emmc", "ext_sd", "sdext",
"sdext1", "sdext2", "sdext3", "sdext4");
final String[] thePath = {""};
Optional<File> optional = StreamSupport.stream(listOfFoldersToSearch)
.filter(new Predicate<String>() {
#Override
public boolean test(final String s) {
File folder = new File(s);
return folder.exists() && folder.isDirectory();
}
}) //I got the ones that exist and are directories
.flatMap(new Function<String, Stream<File>>() {
#Override
public Stream<File> apply(final String s) {
try {
List<File> files = Arrays.asList(new File(s).listFiles());
return StreamSupport.stream(files);
} catch (NullPointerException e) {
return StreamSupport.stream(new ArrayList<File>());
}
}
}) //I got all sub-dirs of the main folders
.flatMap(new Function<File, Stream<File>>() {
#Override
public Stream<File> apply(final File file1) {
if (listOf2DepthFolders.contains(file1.getName()
.toLowerCase())) {
try {
List<File> files = Arrays.asList(file1.listFiles());
return StreamSupport.stream(files);
} catch (NullPointerException e) {
return StreamSupport.stream(Collections.singletonList(file1));
}
} else
return StreamSupport.stream(Collections.singletonList(file1));
}
}) //Here I got all the 2 depth and 3 depth folders
.filter(new Predicate<File>() {
#Override
public boolean test(final File o) {
return listOfExtFolders.contains(o.getName()
.toLowerCase());
}
})
.findFirst();
optional.ifPresent(new Consumer<File>() {
#Override
public void accept(final File file) {
thePath[0] = file.getAbsolutePath();
}
});
Log.e("Path", thePath[0]);
try {
ContextCompat.getExternalFilesDirs(context, null);
} catch (Exception e) {
Log.e("PathException", thePath[0]);
}
return thePath[0];
}
P.S. I tested and verified it on a few HTC and Samsung devices.
This function will return the path of SD Card path.
private String getExternalSdCard(){
String finalPath = null;
File sdCardFile = ContextCompat.getExternalFilesDirs(this, null)[1];
String base = String.format("/Android/data/%s/files", getPackageName());
String path = sdCardFile.getAbsolutePath();
if(path.contains(base)){
finalPath = path.replace(base, "");
}
return finalPath;
}
To get all the list of storage. Use Loop
private String[] storages() {
List<String> storages = new ArrayList<>();
try {
File[] externalStorageFiles = ContextCompat.getExternalFilesDirs(this, null);
String base = String.format("/Android/data/%s/files", getPackageName());
for (File file : externalStorageFiles) {
try {
if (file != null) {
String path = file.getAbsolutePath();
if (path.contains(base)) {
String finalPath = path.replace(base, "");
if (validPath(finalPath)) {
storages.add(finalPath);
}
}
}
} catch (Exception e) {
CrashUtils.report(e);
}
}
} catch (Exception e) {
CrashUtils.report(e);
}
String[] result = new String[storages.size()];
storages.toArray(result);
return result;
}
Related
In my Eclipse project I have a "src" folder that's linked from a one drive folder.
I have some other text files in the linked folder that I want to load with a FileReader.
How would I get this location, optimally in a way that's agnostic to whether the folder is linked or actually in the project folder. I've tried using
MyClass.class.getResource("");
But it returns me a path to the "bin" folder. I'm probably not using it right. The file I want to get is "src/de/lauch/engine/shaders/primitiveTestShader/vertexShader.vsh"
Thanks in advance!
You can create resources folder like that 'src\main\resources' and put the file after that you can run your same code . hopefully it will work.
I solved my particular issue for now but im still open to better solutions :)
public class LinkedResourceLocator {
private static Dictionary<String,String> locations;
public static String getPath(String path) {
if(locations==null) {
File projectLocal = new File(LinkedResourceLocator.class.getClassLoader().getResource("").getPath().replaceAll("%20", " ")).getParentFile();
File dotProject = new File(projectLocal.getAbsolutePath()+"\\.project");
locations = new Hashtable<String,String>();
File[] files = projectLocal.listFiles(new FileFilter(){
#Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for (int i = 0; i < files.length; i++) {
locations.put(files[i].getName(), files[i].getAbsolutePath());
}
try {
BufferedReader br = new BufferedReader(new FileReader(dotProject));
StringBuilder fileContentBuilder = new StringBuilder();
String line;
while((line = br.readLine()) != null) {
fileContentBuilder.append(line.trim());
}
String fileContents = fileContentBuilder.toString();
Pattern p = Pattern.compile("<link><name>(\\w*)</name><type>\\d*</type><location>([\\w/:]*)</location></link>");
Matcher m = p.matcher(fileContents);
while(m.find()) {
locations.put(m.group(1),m.group(2));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.err.println("Can't locate .project file");
} catch (IOException e) {
e.printStackTrace();
System.err.println("Can't read .project file");
}
}
String locator = path.contains("/")?path.substring(0, path.indexOf("/")):path;
String restPath = path.substring(locator.length());
return locations.get(locator)+restPath;
}
}
This class gets the linked resource locations from the eclipse .project file and then converts project local paths like "src/de/lauch/engine/shaders/primitiveTestShader/vertexShader.vsh" to these linked locations.
I am not able get root path usb otg in Android Nougat working fine till marshmallow. even able to get root path of sd card .can any body help me out from this i am frustrated from couple days.
Here is my code that return root path upto marshmallow and nougat sdcard. but not usb otg
public static String FileSystem() {
String path = null;
String SD_CARD_DIR = null;
try {
Process mount = Runtime.getRuntime().exec("mount");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(mount.getInputStream()));
mount.waitFor();
// String extPath = Environment.getExternalStorageDirectory().getPath();
// String isMedai = Environment.getExternalStorageState();
// if(Environment.MEDIA_MOUNTED.equalsIgnoreCase(isMedai)){
// String root = Environment.getRootDirectory().getPath();
// path = Environment.getExternalStoragePublicDirectory(DIRECTORY_EDUCOMP).getPath();
// }
String line;
String strFileSystem = null;
while ((line = bufferedReader.readLine()) != null) {
String[] split = line.split("\\s+");
for (int i = 0; i < split.length - 1; i++) {
if (SD_CARD_DIR == null) {
File mainroot = new File(split[i]);
File f[] = mainroot.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return new File(dir, name).isDirectory();
}
}); // Get First level folders /mnt
if (f != null) {
for (File aFile : f) {
File[] filenames = aFile.listFiles(); // Get second level
// folders
// /mnt/sdcard so on
// and math Educomp
// folder
if (filenames != null) {
for (File ff : filenames) {
String eduFileName = ff.getName();
if (eduFileName.equals("Temp")) {
File[] listEducompfile = ff.listFiles();
if (listEducompfile != null) {
for (File fff : listEducompfile) {
String contentFileName = fff.getName();
if (contentFileName.equals("ts")) {
SD_CARD_DIR = aFile
.getAbsolutePath() + "/";
break;
}
}
}
} else {
File[] filenamesList = ff.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return new File(dir, name).isDirectory();
}
});
if (filenamesList != null) {
for (File fff : filenamesList) {
String eduFileNamess = fff.getName();
if (eduFileNamess.equals("Temp")) {
File[] listEducompfile = fff.listFiles();
if (listEducompfile != null) {
for (File fffds : listEducompfile) {
String contentFileName = fffds.getName();
if (contentFileName.equals("ts")) {
return SD_CARD_DIR = ff + "/";
}
}
}
}
}
}
}
}
}
}
}
}
// SD_CARD_DIR = DEFAULT_SD_CARD_DIR;
}
return SD_CARD_DIR;
}
return path;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
File dir = new File ("/");
File files = dir.listFiles();
You will not get a listing in Nougat for the root directory. You could have told us that.
`files==null` or files.length()==0
Nougat does not allow listing root. There are several other directories too that you cannot list anymore under Nougat.
You can check this approach on Nougat. But there is no way to make difference between removable SD card and USB flash if they are both connected to your device simultaneously.
Your approach - parsing mount file - does not work for some (chineese?) devices because string entry for internal memory may be completely the same as for removable SD card.
P.S. It is a user responsibility to find out where is USB flash or removable SD card in a "well" designed app. You should not do that by himself because Android does not provide public API for this purpose except Intent.ACTION_OPEN_DOCUMENT_TREE to call a built-in file chooser to interact with user in order to choose folder.
P.P.S INTERACTION WITH USER:
Create button with name "Show USB OTG Root" and onClick method containing
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.putExtra("android.content.extra.SHOW_ADVANCED", true);//http://stackoverflow.com/questions/28605278/android-5-sd-card-label
startActivityForResult(intent, REQUEST_CODE_USB_ACCESS);
In onActivityResult callback you have to catch user answer when he choose USB OTG root in internal Android chooser:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_USB_ACCESS:
if (data.getData() != null) {
int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(data.getData(), takeFlags);
DocumentFile documentFile = DocumentFile.fromTreeUri(this, data.getData());
}
}
}
documentFile is an access object representing USB OTG root (if user did not make mistake when choosing). You can make some file operation like documentFile.listFiles() on it. There is no other way to operate with files on removable media in public API starting from Lollipop. I.e. your desired path to USB OTG can not be obtained as a string from some public API method.
I have a xml file that I'm getting its full path, and pass it to a function where I add a String to its name. However I'm not being able to use it (the initial fullpath) after adding the string. How can it be done, that after getting the fullpath in search(String dirName), and adding the string in lk(String fullpath), I can still use the path which is returned by search(String dirName).
public String search( String dirName)throws Exception{
String fullPath = null;
File dir = new File(dirName);
if ( dir.isDirectory() )
{
String[] list = dir.list(new FilenameFilter()
{
#Override
public boolean accept(File f, String s )
{
return s.endsWith(".xml");
}
});
if ( list.length > 0 )
{
fullPath = dirName+list[0];
lockFile(fullPath);
return fullPath;
}
}
return "";
}
public void lk( String fullPath) throws Exception {
File f = new File(fullPath);
String fileNameWithExt = f.getName();
try {
File newfile =new File(fileNameWithExt+".lock");
if(f.renameTo(newfile)){
System.out.println("Rename succesful");
}else{
System.out.println("Rename failed");
}
} catch (Exception e) {
e.printStackTrace();
}
}
try this
File originalFile = new File(<file parent path>, "myxmlfile");
File cloneFile = new File(originalFile.getParent(),
originalFile.getName()+"<anything_i_want_to_add>");
Files.copy(originalFile.toPath(),cloneFile.toPath());
//now your new file exist and you can use it
originalFile.delete();//you delete the original file
...
//after you are done with everything and you want the path back
Files.copy(cloneFile.toPath(),originalFile.toPath());
cloneFile.delete();
In your lock method, you are calling renameTo method. Because of that, the original filename is now gone, and is replaced by the new filename that ends with .lock.
The java.io.File class is not a file pointer but an object to hold a filename. Using a file object that still refers to an old filename will cause an error.
To answer your question: If you want the old filename after locking, you must use a different approach in locking your file. For example, MS Access locks their .accdb files by creating a lockfile with the same filename as the opened .accdb file.
You may use this code as a reference:
public boolean fileIsLocked(File file) {
File lock = new File(file.getAbsolutePath() + ".lock");
return lock.exists();
}
public void lockFile(File file) {
if (!fileIsLocked(file)) {
File lock = new File(file.getAbsolutePath() + ".lock");
lock.createNewFile();
lock.deleteOnExit(); // unlocks file on JVM exit
}
}
public void unlockFile(File file) {
if (fileIsLocked(file)) {
File lock = new File(file.getAbsolutePath() + ".lock");
lock.delete();
}
}
I am doing a simple application that loads and saves files in java. I am trying to port it over to Android and am having trouble getting it to see the file.
The file path I am currently using is
private static final String SAVE_FILE_PATH = "data/save";
Here is the function that loads the data from the file:
public void loadData() throws FileNotFoundException {
File file = new File(SAVE_FILE_PATH);
Scanner scanner;
if (file.exists()) {
scanner = new Scanner(new FileInputStream(file));
try {
while (scanner.hasNextLine()) {
allPlayers.add(new Player(scanner.nextLine()));
}
} finally {
scanner.close();
}
}
else {
System.out.println("No file found");
}
} finally {
scanner.close();
}
}
}
While getExternalStorageDirectory() gets you the path to the SD card, consider using Activity.getExternalFilesDir() which will return (and create if necessary) a directory that's nominally private to your application. It also has the advantage that it will be auto-deleted for you if the application is uninstalled. This is new in API 8, so you might not want to use it if you're supporting older devices.
Otherwise, you'll have to follow ρяσѕρєя K's advice. Don't forget to create the storage directory you want to use. My code typically looks like this:
/**
* Utility: Return the storage directory. Create it if necessary.
*/
public static File dataDir()
{
File sdcard = Environment.getExternalStorageDirectory();
if( sdcard == null || !sdcard.isDirectory() ) {
// TODO: warning popup
Log.w(TAG, "Storage card not found " + sdcard);
return null;
}
File datadir = new File(sdcard, "MyApplication");
if( !confirmDir(datadir) ) {
// TODO: warning popup
Log.w(TAG, "Unable to create " + datadir);
return null;
}
return datadir;
}
/**
* Create dir if necessary, return true on success
*/
public static final boolean confirmDir(File dir) {
if( dir.isDirectory() ) return true;
if( dir.exists() ) return false;
return dir.mkdirs();
}
Now use this to specify your save file:
File file = new File(dataDir(), "save");
Scanner scanner;
if (file.exists()) {
// etc.
}
I create some folders into assets. Each folder contains files that I would like to list. I am using following code but I always get a null value for fileList. Thank you.
I used, listFiles("/assets/images/","nothing");
private void listFiles(String dirFrom, String dirTo) {
File f = new File(dirFrom);
String fileList[] = f.list();
if (fileList != null)
{
for ( int i = 0;i<fileList.length;i++)
{
Log.d("",fileList[i]);
}
}
}
You'll probably want to do this:
private void listFiles(String dirFrom) {
Resources res = getResources(); //if you are in an activity
AssetManager am = res.getAssets();
String fileList[] = am.list(dirFrom);
if (fileList != null)
{
for ( int i = 0;i<fileList.length;i++)
{
Log.d("",fileList[i]);
}
}
}
Also your function call should be: listFiles("images"); if you want to list images.
Simplest would surely be this:
String[] fileList = getAssets().list("images");