/** * Create a folder. The folder may even be on external SD card for Kitkat. * * @param file The folder to be created. * @return True if creation was successful. */ public static boolean mkdir(final File file, Context context) { if (file == null) return false; if (file.exists()) { // nothing to create. return file.isDirectory(); } // Try the normal way if (file.mkdirs()) { return true; } // Try with Storage Access Framework. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && FileUtil.isOnExtSdCard(file, context)) { DocumentFile document = getDocumentFile(file, true, context); // getDocumentFile implicitly creates the directory. return document.exists(); } // Try the Kitkat workaround. if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { try { return MediaStoreHack.mkdir(context, file); } catch (IOException e) { return false; } } return false; }
/** * Check for a directory if it is possible to create files within this directory, either via * normal writing or via Storage Access Framework. * * @param folder The directory * @return true if it is possible to write in this directory. */ public static final boolean isWritableNormalOrSaf(final File folder, Context c) { // Verify that this is a directory. if (folder == null) return false; if (!folder.exists() || !folder.isDirectory()) { return false; } // Find a non-existing file in this directory. int i = 0; File file; do { String fileName = "AugendiagnoseDummyFile" + (++i); file = new File(folder, fileName); } while (file.exists()); // First check regular writability if (isWritable(file)) { return true; } // Next check SAF writability. DocumentFile document = getDocumentFile(file, false, c); if (document == null) { return false; } // This should have created the file - otherwise something is wrong with access URL. boolean result = document.canWrite() && file.exists(); // Ensure that the dummy file is not remaining. document.delete(); return result; }
/** * Delete a file. May be even on external SD card. * * @param file the file to be deleted. * @return True if successfully deleted. */ public static final boolean deleteFile(@NonNull final File file, Context context) { // First try the normal deletion. boolean fileDelete = deleteFilesInFolder(file, context); if (file.delete() || fileDelete) return true; // Try with Storage Access Framework. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && FileUtil.isOnExtSdCard(file, context)) { DocumentFile document = getDocumentFile(file, false, context); return document.delete(); } // Try the Kitkat workaround. if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { ContentResolver resolver = context.getContentResolver(); try { Uri uri = MediaStoreUtil.getUriFromFile(file.getAbsolutePath(), context); resolver.delete(uri, null, null); return !file.exists(); } catch (Exception e) { Log.e("AmazeFileUtils", "Error when deleting file " + file.getAbsolutePath(), e); return false; } } return !file.exists(); }
private DocumentFile getDCIMDocumentFolder(boolean create) { DocumentFile documentFile = null; DocumentFile sdDir; if ((sdDir = getExternalSdDocumentFile()) != null) { documentFile = sdDir.findFile("DCIM"); if (documentFile == null && create) documentFile = sdDir.createDirectory("DCIM"); } return documentFile; }
@Override public DocumentFile getFreeDcamDocumentFolder() { DocumentFile dcimfolder; DocumentFile freedcamfolder = null; if ((dcimfolder = getDCIMDocumentFolder(true)) != null) { freedcamfolder = dcimfolder.findFile("FreeDcam"); if (freedcamfolder == null) freedcamfolder = dcimfolder.createDirectory("FreeDcam"); } return freedcamfolder; }
/** * Rename a folder. In case of extSdCard in Kitkat, the old folder stays in place, but files are * moved. * * @param source The source folder. * @param target The target folder. * @return true if the renaming was successful. */ public static final boolean renameFolder( @NonNull final File source, @NonNull final File target, Context context) { // First try the normal rename. if (new Futils().rename(source, target.getName(), false)) { return true; } if (target.exists()) { return false; } // Try the Storage Access Framework if it is just a rename within the same parent folder. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && source.getParent().equals(target.getParent()) && FileUtil.isOnExtSdCard(source, context)) { DocumentFile document = getDocumentFile(source, true, context); if (document.renameTo(target.getName())) { return true; } } // Try the manual way, moving files individually. if (!mkdir(target, context)) { return false; } File[] sourceFiles = source.listFiles(); if (sourceFiles == null) { return true; } for (File sourceFile : sourceFiles) { String fileName = sourceFile.getName(); File targetFile = new File(target, fileName); if (!copyFile(sourceFile, targetFile, context)) { // stop on first error return false; } } // Only after successfully copying all files, delete files on source folder. for (File sourceFile : sourceFiles) { if (!deleteFile(sourceFile, context)) { // stop on first error return false; } } return true; }
/** * Get a DocumentFile corresponding to the given file (for writing on ExtSdCard on Android 5). If * the file is not existing, it is created. * * @param file The file. * @param isDirectory flag indicating if the file should be a directory. * @return The DocumentFile */ public static DocumentFile getDocumentFile( final File file, final boolean isDirectory, Context context) { String baseFolder = getExtSdCardFolder(file, context); boolean originalDirectory = false; if (baseFolder == null) { return null; } String relativePath = null; try { String fullPath = file.getCanonicalPath(); if (!baseFolder.equals(fullPath)) relativePath = fullPath.substring(baseFolder.length() + 1); else originalDirectory = true; } catch (IOException e) { return null; } catch (Exception f) { originalDirectory = true; // continue } String as = PreferenceManager.getDefaultSharedPreferences(context).getString("URI", null); Uri treeUri = null; if (as != null) treeUri = Uri.parse(as); if (treeUri == null) { return null; } // start with root of SD card and then parse through document tree. DocumentFile document = DocumentFile.fromTreeUri(context, treeUri); if (originalDirectory) return document; String[] parts = relativePath.split("\\/"); for (int i = 0; i < parts.length; i++) { DocumentFile nextDocument = document.findFile(parts[i]); if (nextDocument == null) { if ((i < parts.length - 1) || isDirectory) { nextDocument = document.createDirectory(parts[i]); } else { nextDocument = document.createFile("image", parts[i]); } } document = nextDocument; } return document; }
public static boolean rmdir(final File file, Context context) { if (file == null) return false; if (!file.exists()) { return true; } if (!file.isDirectory()) { return false; } String[] fileList = file.list(); if (fileList != null && fileList.length > 0) { // empty the folder. rmdir1(file, context); } String[] fileList1 = file.list(); if (fileList1 != null && fileList1.length > 0) { // Delete only empty folder. return false; } // Try the normal way if (file.delete()) { return true; } // Try with Storage Access Framework. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { DocumentFile document = getDocumentFile(file, true, context); return document.delete(); } // Try the Kitkat workaround. if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { ContentResolver resolver = context.getContentResolver(); ContentValues values = new ContentValues(); values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath()); resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); // Delete the created entry, such that content provider will delete the file. resolver.delete( MediaStore.Files.getContentUri("external"), MediaStore.MediaColumns.DATA + "=?", new String[] {file.getAbsolutePath()}); } return !file.exists(); }
@Override public DocumentFile getExternalSdDocumentFile() { DocumentFile sdDir = null; String extSdFolder = appSettingsManager.GetBaseFolder(); if (extSdFolder == null || extSdFolder.equals("")) return null; Uri uri = Uri.parse(extSdFolder); sdDir = DocumentFile.fromTreeUri(getContext(), uri); return sdDir; }
@Nullable private boolean deletFile(File file) { if (!file.delete()) { DocumentFile sdDir = getExternalSdDocumentFile(); if (sdDir == null) return false; String baseS = sdDir.getName(); String fileFolder = file.getAbsolutePath(); String[] split = fileFolder.split("/"); DocumentFile tmpdir = null; boolean append = false; for (String aSplit : split) { if (aSplit.equals(baseS) || append) { if (!append) { append = true; tmpdir = sdDir; } else { tmpdir = tmpdir.findFile(aSplit); } } } boolean d = false; d = !(tmpdir != null && tmpdir.exists()) || tmpdir.delete(); Logger.d("delteDocumentFile", "file delted:" + d); return d; } return true; }
public static boolean mkfile(final File file, Context context) throws IOException { if (file == null) return false; if (file.exists()) { // nothing to create. return !file.isDirectory(); } // Try the normal way try { if (file.createNewFile()) { return true; } } catch (IOException e) { e.printStackTrace(); } boolean b = true; // Try with Storage Access Framework. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && FileUtil.isOnExtSdCard(file, context)) { DocumentFile document = getDocumentFile(file.getParentFile(), true, context); // getDocumentFile implicitly creates the directory. try { b = document.createFile(MimeTypes.getMimeType(file), file.getName()) != null; return b; } catch (Exception e) { e.printStackTrace(); return false; } } if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { try { return MediaStoreHack.mkfile(context, file); } catch (Exception e) { return false; } } return false; }
public static OutputStream getOutputStream(@NonNull final File target, Context context, long s) { OutputStream outStream = null; try { // First try the normal way if (isWritable(target)) { // standard way outStream = new FileOutputStream(target); } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Storage Access Framework DocumentFile targetDocument = getDocumentFile(target, false, context); outStream = context.getContentResolver().openOutputStream(targetDocument.getUri()); } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { // Workaround for Kitkat ext SD card return MediaStoreHack.getOutputStream(context, target, s); } } } catch (Exception e) { Log.e("AmazeFileUtils", "Error when copying file from " + target.getAbsolutePath(), e); } return outStream; }
/** * Copy a file. The target file may even be on external SD card for Kitkat. * * @param source The source file * @param target The target file * @return true if the copying was successful. */ @SuppressWarnings("null") public static boolean copyFile(final File source, final File target, Context context) { FileInputStream inStream = null; OutputStream outStream = null; FileChannel inChannel = null; FileChannel outChannel = null; try { inStream = new FileInputStream(source); // First try the normal way if (isWritable(target)) { // standard way outStream = new FileOutputStream(target); inChannel = inStream.getChannel(); outChannel = ((FileOutputStream) outStream).getChannel(); inChannel.transferTo(0, inChannel.size(), outChannel); } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Storage Access Framework DocumentFile targetDocument = getDocumentFile(target, false, context); outStream = context.getContentResolver().openOutputStream(targetDocument.getUri()); } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { // Workaround for Kitkat ext SD card Uri uri = MediaStoreUtil.getUriFromFile(target.getAbsolutePath(), context); outStream = context.getContentResolver().openOutputStream(uri); } else { return false; } if (outStream != null) { // Both for SAF and for Kitkat, write to output stream. byte[] buffer = new byte[16384]; // MAGIC_NUMBER int bytesRead; while ((bytesRead = inStream.read(buffer)) != -1) { outStream.write(buffer, 0, bytesRead); } } } } catch (Exception e) { Log.e( "AmazeFileUtils", "Error when copying file from " + source.getAbsolutePath() + " to " + target.getAbsolutePath(), e); return false; } finally { try { inStream.close(); } catch (Exception e) { // ignore exception } try { outStream.close(); } catch (Exception e) { // ignore exception } try { inChannel.close(); } catch (Exception e) { // ignore exception } try { outChannel.close(); } catch (Exception e) { // ignore exception } } return true; }