I generated a text file and tried to save it. It doesn't work only on android Q. On android 9 , 8 and 7 it works. When I check if file exists on android 10 it works but I don't it on device . I do this :
private void createFile(Context ctx, String fileName, String text) {
File filesDir = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
filesDir = ctx.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
}
assert filesDir != null;
if (!filesDir.exists()){
if(filesDir.mkdirs()){
}
}
File file = new File(filesDir, fileName + ".txt");
try {
if (!file.exists()) {
if (!file.createNewFile()) {
throw new IOException("Cant able to create file");
}
}
OutputStream os = new FileOutputStream(file);
byte[] data = text.getBytes();
os.write(data);
os.flush();
os.close();
Log.e("TAG", "File Path= " + file.toString());
if(file.exists()){
Log.e("d","d");
}
File fileTemp = new File(file.getPath());
FileInputStream notes_xml = new FileInputStream(fileTemp);
byte fileContent[] = new byte[(int)notes_xml.available()];
//The information will be content on the buffer.
notes_xml.read(fileContent);
String strContent = new String(fileContent);
Log.e("content",strContent);
notes_xml.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Since Android 10 (API 29) I need to use the Storage Access Framework's File Picker to select GPX (GPS) files to copy from the Downloads folder to my local app folder. I have implemented the file picker and am able to select the GPX file, however the result data URI appears different to the filename (but unique) and I cannot seem to use it to copy the files. The rest of the code is the same "copy" code I used in previous versions of Android. What am I doing wrong and how should I best use the SAF File Picker to copy files? I haven't been able to find a recent (API 29) "file copy" example on the net...
private static final int READ_REQUEST_CODE = 42;
...
public void performFileSearch() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
// intent.setType("application/gpx"); // Filters GPX file but wont let me select them.
intent.setType("*/*");
startActivityForResult(intent, READ_REQUEST_CODE);
}
...
if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
Uri uri = null;
if (data != null) {
uri = data.getData();
handleDownloadedGPXFiles2(uri);
}
}
...
private void handleDownloadedGPXFiles2(Uri selectedFileUri) {
File sourceFile = new File(selectedFileUri.getPath()); // Returns a unique number or string but NOT filename string???
File destDirectory = new File(this.getExternalFilesDir(null), "Imported");
File destFile = new File(destDirectory, "test.gpx"); // Needs to be same name as original filename.
try {
if (!destFile.exists()) {
destFile.createNewFile();
}
FileInputStream inStream = new FileInputStream(sourceFile);
FileOutputStream outStream = new FileOutputStream(destFile);
FileChannel inChannel = inStream.getChannel();
FileChannel outChannel = outStream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inStream.close();
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), "File Import Complete", Toast.LENGTH_LONG).show();
}
File sourceFile = new File(selectedFileUri.getPath());
Remove above line.
FileInputStream inStream = new FileInputStream(sourceFile);
Replace that line by:
InputStream inStream = getContentResolver().openInputStream(selectedFileUri);
Further you can remove
if (!destFile.exists()) {
destFile.createNewFile();
}
as the file will be created by the new FileOutputStream();
Finally: Your last Toast() is on the wrong place. It should be in the try block.
Place a different Toast() in the catch block to inform yourself or the user.
Thanks blackapps. Final code works well...
private void handleDownloadedGPXFiles2(Uri selectedFileUri) {
String displayName = "imported.gpx";
String fileExtension;
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(selectedFileUri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
if (displayName != null && displayName.length() >=4) {
fileExtension = displayName.substring(displayName.length() - 4);
if (!fileExtension.equals(".gpx")){
myCustomToast("Must be a .GPX file!");
return;
}
} else {
myCustomToast("Must be a .GPX file!");
return;
}
}
File destDirectory = new File(this.getExternalFilesDir(null), "Imported");
File destFile = new File(destDirectory, displayName);
FileOutputStream outStream = new FileOutputStream(destFile);
InputStream in = getContentResolver().openInputStream(selectedFileUri);
OutputStream out = outStream;
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
out.flush();
out.close();
Toast.makeText(getApplicationContext(), "File Import Complete", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "File Import FAILED", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
finally
{
if (cursor != null)
cursor.close();
}
}
I would like to decode a base64 string and turn it into a file (as PDF/JPG) and save it to device, how for example in (/storage/emulated/0/Download/file.pdf).
For encode a file I use this code:
File originalFile = new File("/mnt/sdcard/download/file.pdf");
String encodedBase64 = null;
try {
FileInputStream fileInputStreamReader = new FileInputStream(originalFile);
byte[] bytes = new byte[(int) originalFile.length()];
fileInputStreamReader.read(bytes);
encodedBase64=Base64.encodeToString(bytes,Base64.NO_WRAP);
messaggio=encodedBase64.toString();
//encodedBase64 = new String(Base64.encode(bytes));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Now, I would like to decode this base64 string and convert it into a file and save it on the device.
You can try this:
FileOutputStream fos = new FileOutputStream(filepath);
fos.write(Base64.decode(base64String, Base64.NO_WRAP));
fos.close();
Where:
filepath: Path to the new file
base64String: Your base64 string that you want to convert
Give READ_STORAGE and Write_STORAGE Permission in Manifest and dont forget for RunTime Permission.
public static void storetoPdfandOpen(Context context, String base) {
String root = Environment.getExternalStorageDirectory().toString();
Log.d("ResponseEnv",root);
File myDir = new File(root + "/WorkBox");
if (!myDir.exists()) {
myDir.mkdirs();
}
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Attachments-" + n + ".pdf";
File file = new File(myDir, fname);
if (file.exists())
file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
byte[] pdfAsBytes = Base64.decode(base, 0);
out.write(pdfAsBytes);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
File dir = new File(Environment.getExternalStorageDirectory(), "WorkBox");
File imgFile = new File(dir, fname);
Intent sendIntent = new Intent(Intent.ACTION_VIEW);
Uri uri;
if (Build.VERSION.SDK_INT < 24) {
uri = Uri.fromFile(file);
} else {
uri = Uri.parse("file://" + imgFile); // My work-around for new SDKs, causes ActivityNotFoundException in API 10.
}
sendIntent.setDataAndType(uri, "application/pdf");
sendIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(sendIntent);
}
How do I upload a photo using a URL in the playframework?
I was thinking like this:
URL url = new URL("http://www.google.ru/intl/en_com/images/logo_plain.png");
BufferedImage img = ImageIO.read(url);
File newFile = new File("google.png");
ImageIO.write(img, "png", newFile);
But maybe there's another way. In the end I have to get the File and file name.
Example controller:
public static Result uploadPhoto(String urlPhoto){
Url url = new Url(urlPhoto); //doSomething
//get a picture and write to a temporary file
File tempPhoto = myUploadPhoto;
uploadFile(tempPhoto); // Here we make a copy of the file and save it to the file system.
return ok('something');
}
To get that photo you can use The play WS API, the code behind is an example extracted from the play docs in the section Processing large responses, I recommend you to read the full docs here
final Promise<File> filePromise = WS.url(url).get().map(
new Function<WSResponse, File>() {
public File apply(WSResponse response) throws Throwable {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = response.getBodyAsStream();
// write the inputStream to a File
final File file = new File("/tmp/response.txt");
outputStream = new FileOutputStream(file);
int read = 0;
byte[] buffer = new byte[1024];
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
return file;
} catch (IOException e) {
throw e;
} finally {
if (inputStream != null) {inputStream.close();}
if (outputStream != null) {outputStream.close();}
}
}
}
);
Where url is :
String url = "http://www.google.ru/intl/en_com/images/logo_plain.png"
This is as suggested in play documentation for large files:
*
When you are downloading a large file or document, WS allows you to
get the response body as an InputStream so you can process the data
without loading the entire content into memory at once.
*
Pretty much the same as the above answer then some...
Route: POST /testFile 'location of your controller goes here'
Request body content: {"url":"http://www.google.ru/intl/en_com/images/logo_plain.png"}
Controller(using code from JavaWS Processing large responses):
public static Promise<Result> saveFile() {
//you send the url in the request body in order to avoid complications with encoding
final JsonNode body = request().body().asJson();
// use new URL() to validate... not including it for brevity
final String url = body.get("url").asText();
//this one's copy/paste from Play Framework's docs
final Promise<File> filePromise = WS.url(url).get().map(response -> {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = response.getBodyAsStream();
final File file = new File("/temp/image");
outputStream = new FileOutputStream(file);
int read = 0;
byte[] buffer = new byte[1024];
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
return file;
} catch (IOException e) {
throw e;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}); // copy/paste ended
return filePromise.map(file -> (Result) ok(file.getName() + " saved!")).recover(
t -> (Result) internalServerError("error -> " + t.getMessage()));
}
And that's it...
In order to serve the file after the upload phase you can use this answer(I swear I'm not promoting myself...): static asset serving from absolute path in play framework 2.3.x
Good day!
I have just started developing for android. In my app, I need to copy the items in my assets folder to the internal storage.
I have searched a lot on SO including this which copies it to the external storage.
How to copy files from 'assets' folder to sdcard?
This is what I want to achieve:
I have a directory already present in the internal storage as X>Y>Z. I need a file to be copied to Y and another to Z.
Can anyone help me out with a code snippet? I really don't have any idea how to go on about this.
Sorry for my bad English.
Thanks a lot.
Use
String out= Environment.getExternalStorageDirectory().getAbsolutePath() + "/X/Y/Z/" ;
File outFile = new File(out, Filename);
After Editing in your ref. Link Answer.
private void copyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
for(String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
String outDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/X/Y/Z/" ;
File outFile = new File(outDir, filename);
out = new FileOutputStream(outFile);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
I did something like this. This allows you to copy all the directory structure to copy from Android AssetManager.
public String copyDirorfileFromAssetManager(String arg_assetDir, String arg_destinationDir) throws IOException
{
File sd_path = Environment.getExternalStorageDirectory();
String dest_dir_path = sd_path + addLeadingSlash(arg_destinationDir);
File dest_dir = new File(dest_dir_path);
createDir(dest_dir);
AssetManager asset_manager = getApplicationContext().getAssets();
String[] files = asset_manager.list(arg_assetDir);
for (int i = 0; i < files.length; i++)
{
String abs_asset_file_path = addTrailingSlash(arg_assetDir) + files[i];
String sub_files[] = asset_manager.list(abs_asset_file_path);
if (sub_files.length == 0)
{
// It is a file
String dest_file_path = addTrailingSlash(dest_dir_path) + files[i];
copyAssetFile(abs_asset_file_path, dest_file_path);
} else
{
// It is a sub directory
copyDirorfileFromAssetManager(abs_asset_file_path, addTrailingSlash(arg_destinationDir) + files[i]);
}
}
return dest_dir_path;
}
public void copyAssetFile(String assetFilePath, String destinationFilePath) throws IOException
{
InputStream in = getApplicationContext().getAssets().open(assetFilePath);
OutputStream out = new FileOutputStream(destinationFilePath);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0)
out.write(buf, 0, len);
in.close();
out.close();
}
public String addTrailingSlash(String path)
{
if (path.charAt(path.length() - 1) != '/')
{
path += "/";
}
return path;
}
public String addLeadingSlash(String path)
{
if (path.charAt(0) != '/')
{
path = "/" + path;
}
return path;
}
public void createDir(File dir) throws IOException
{
if (dir.exists())
{
if (!dir.isDirectory())
{
throw new IOException("Can't create directory, a file is in the way");
}
} else
{
dir.mkdirs();
if (!dir.isDirectory())
{
throw new IOException("Unable to create directory");
}
}
}
try this below code
private void copyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
for(String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
File outFile = new File(getExternalFilesDir(null), filename);
out = new FileOutputStream(outFile);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
This is my Kotlin solution with auto-closable streams to copy in internal app storage:
val copiedFile = File(context.filesDir, "copied_file.txt")
context.assets.open("original_file.txt").use { input ->
copiedFile.outputStream().use { output ->
input.copyTo(output, 1024)
}
}
My small solution on Kotlin, for copy data from assets to INTERNAL STORAGE
fun copy() {
val bufferSize = 1024
val assetManager = context.assets
val assetFiles = assetManager.list("")
assetFiles.forEach {
val inputStream = assetManager.open(it)
val outputStream = FileOutputStream(File(context.filesDir, it))
try {
inputStream.copyTo(outputStream, bufferSize)
} finally {
inputStream.close()
outputStream.flush()
outputStream.close()
}
}
}
public void addFilesToSystem(String sysName, String intFil, Context c){
//sysName is the name of the file we have in the android os
//intFil is the name of the internal file
file = new File(path, sysName + ".txt");
if(!file.exists()){
path.mkdirs();
try {
AssetManager am = c.getAssets();
InputStream is = am.open(intFil);
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
os.write(data);
is.close();
os.close();
Toast t = Toast.makeText(c, "Making file: " + file.getName() + ". One time action", Toast.LENGTH_LONG);
t.show();
//Update files for the user to use
MediaScannerConnection.scanFile(c,
new String[] {file.toString()},
null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
// TODO Auto-generated method stub
}
});
} catch (IOException e) {
Toast t = Toast.makeText(c, "Error: " + e.toString() + ". One time action", Toast.LENGTH_LONG);
t.show();
e.printStackTrace();
}
}
}
To add a file, call the addFilesToSystem("this_file_is_in_the_public_system", "this_file_is_in_the_assets_folder", context/this context is if you do not have the method in the Activity/
Hope it helps
You can use the Envrionment#getDataDirectory method for that. It'll give the path of the data directory of the internal storage memory. This is generally where all the app related data is stored.
Alternately, if you want to store in the root directory, you can use the Environment#getRootDirectory method for that.
If you need to copy any file from assets to the internal storage and do it only once:
public void writeFileToStorage() {
Logger.d(TAG, ">> writeFileToStorage");
AssetManager assetManager = mContext.getAssets();
if (new File(getFilePath()).exists()) {
Logger.d(TAG, "File exists, do nothing");
Logger.d(TAG, "<< writeFileToStorage");
return;
}
try (InputStream input = assetManager.open(FILE_NAME);
OutputStream output = new FileOutputStream(getFilePath())) {
Logger.d(TAG, "File does not exist, write it");
byte[] buffer = new byte[input.available()];
int length;
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
Logger.e(TAG, "File is not found");
} catch (IOException e) {
e.printStackTrace();
Logger.d(TAG, "Error while writing the file");
}
Logger.d(TAG, "<< writeFileToStorage");
}
public String getFilePath() {
String filePath = mContext.getFilesDir() + "/" + FILE_NAME;
Logger.d(TAG, "File path: " + filePath);
return filePath;
}