I have been struggling for two days to try and understand the process of copying a file to the SD card in Android. None of the methods I tried thus far seem to work.
My application has a Profile Picture setting. I need to launch an Intent to pick an Image, then I need to copy the Image to a new Path on the SD Card and then return the Uri of the new Image at which point I check the Images Orientation (Samsung Pics seem to be rotated 90 degrees sometimes). I then rotate the Image correctly and then save the Uri to a SharedPreferences File for use in the Application.
This is my Intent Call:
case R.id.ib_userImage:
i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(i, 1);
break;
This is my current horrific attempt at the copy function, I have changed it so much I am not very lost.
public static void copyImage(Context context, Uri uri) {
Log.i("ATTENTION", "Inside the Copy Function");
Log.i("ATTENTION", "Trying to copy file: " + uri.toString());
try {
String outputPath = Environment.getExternalStorageDirectory() + "/appname/images/";
File dir = new File(outputPath);
if(!dir.exists()) {
dir.mkdirs();
}
Log.i("ATTENTION", "Destination File Created at: " + dir.toURI().toString());
InputStream in = context.getContentResolver().openInputStream(uri);
OutputStream out = new FileOutputStream(dir);
byte[] buffer = new byte[1024];
while(in.read(buffer) > 0) {
out.write(buffer);
}
out.flush();
out.close();
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Log.i("ATTENTION", "File Copied");
}
Thank you for the help, I will provide any other information you might need.
Update:
I am now getting the Following Exception During the Write Process
java.io.FileNotFoundException: /storage/emulated/0/appname/images: open failed: EISDIR (Is a Directory);
My Understaing is that I specified a Directory with the following code:
String outputPath = Environment.getExternalStorageDirectory() + "/medinfo/images/";
File dir = new File(outputPath);
if(!dir.exists()) {
dir.mkdirs();
}
and then passed it to the OutputStream:
OutputStream out = new FileOutputStream(dir);
and the OutputStream would create the file for me within that Directory.
I didn't think that was actually trying to open the Directory.
Usual problem. Don't ignore the count returned by read().
while ((count = in,read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
EDIT Your directory problem is cured by:
dir.getParentFile().mkdirs();
and removing the redundant existence check. At present you are creating the file itself as a directory.
Related
I would like to move a file from the download folder to a folder in my app, I have seen that you can use the Files.move (source, destination) function, but I don't know how to get the source and destination path.
When y try
String sdCard = Environment.getExternalStorageDirectory().toString();
File ficheroPrueba = new File(sdCard + "/pau_alem18je_compressed.pdf");
if(ficheroPrueba.exists())
Log.v(TAG, "Hola")
}
Despite having downloaded the file (it is seen in the android emulator in downloads) it does not print the log.v
Use Environment.getExternalStorageDirectory() to get to the root of external storage (which, on some devices, is an SD card).
String sdCard = Environment.getExternalStorageDirectory().toString();
// the file to be moved or copied
File sourceLocation = new File (sdCard + "/sample.txt");
// make sure your target location folder exists!
File targetLocation = new File (sdCard + "/MyNewFolder/sample.txt");
// just to take note of the location sources
Log.v(TAG, "sourceLocation: " + sourceLocation);
Log.v(TAG, "targetLocation: " + targetLocation);
try {
// 1 = move the file, 2 = copy the file
int actionChoice = 2;
// moving the file to another directory
if(actionChoice==1){
if(sourceLocation.renameTo(targetLocation)){
Log.v(TAG, "Move file successful.");
}else{
Log.v(TAG, "Move file failed.");
}
}
// we will copy the file
else{
// make sure the target file exists
if(sourceLocation.exists()){
InputStream in = new FileInputStream(sourceLocation);
OutputStream out = new FileOutputStream(targetLocation);
// Copy the bits from instream to outstream
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
Log.v(TAG, "Copy file successful.");
}else{
Log.v(TAG, "Copy file failed. Source file missing.");
}
}
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
Everyone: I am trying to send a folder (there are many files inside this folder) via email in Android Development.
First, I tried send the whole folder directly by using a click event and intent event.
My first attempt code shows the following:
My first part of code is onclicklistener event:
listView.setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(int position, SwipeMenu menu,int index) {
switch (index) {
case 0:
sendEmail(list.get(position).getName());
break;
case 1:
list.remove(position);
adapter.notifyDataSetChanged();
}
return false;
}
});
My second code to send Email is as follows:
public void sendEmail(String data_path){
Intent email = new Intent(Intent.ACTION_SEND);
File file_location = new File(SDCard, data_path);
email.setType("vnd.android.cursor.dir/email");
email.putExtra(Intent.EXTRA_EMAIL, new String[]{"example#gmail.com"}); //set up email
email.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file_location)); //add attachment
email.putExtra(Intent.EXTRA_SUBJECT, "Subject");
startActivity(Intent.createChooser(email, "pick an Email provider"));
}
When I run this code, it works fine to jump into email sender, but without any folder implement, the email implement is empty.
I am wondering if it is impossible to send a folder directly via email.
Now I am trying to another way to solve this: I am planning to compress folder(.zip) first and then send the zip file to email in just one click event, But I can not find any solutions showing how to compress the folder and send zip file in just one click event, What I mean is that I want a solution which:
Clicks the file that needs to be sent (click event has finished)
After it triggers the click event, the app will compress the clicked file to a zip file.
The zip file will automatically add as mail implements that waits to be sent
I was trapped there for many days and still failed to find any answers, I also search on StackOverflow, but most questions are about how to compress a file or send file by email. I am looking for a way to compress a folder and send a zip file in one click event.
If you have any ideas, I would quite appreciate them!
Here is a workaround to transform your folder into zip.
First, grant permissions:
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
And then use this to transform your folder:
/*
*
* Zips a file at a location and places the resulting zip file at the toLocation
* Example: zipFileAtPath("downloads/myfolder", "downloads/myFolder.zip");
*/
public boolean zipFileAtPath(String sourcePath, String toLocation) {
final int BUFFER = 2048;
File sourceFile = new File(sourcePath);
try {
BufferedInputStream origin = null;
FileOutputStream dest = new FileOutputStream(toLocation);
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
dest));
if (sourceFile.isDirectory()) {
zipSubFolder(out, sourceFile, sourceFile.getParent().length());
} else {
byte data[] = new byte[BUFFER];
FileInputStream fi = new FileInputStream(sourcePath);
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(getLastPathComponent(sourcePath));
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER)) != -1) {
out.write(data, 0, count);
}
}
out.close();
} catch (Exception e) {
e.printStackTrace();
return false;
}
Here is another example:
private static void zipFolder(String inputFolderPath, String outZipPath) {
try {
FileOutputStream fos = new FileOutputStream(outZipPath);
ZipOutputStream zos = new ZipOutputStream(fos);
File srcFile = new File(inputFolderPath);
File[] files = srcFile.listFiles();
Log.d("", "Zip directory: " + srcFile.getName());
for (int i = 0; i < files.length; i++) {
Log.d("", "Adding file: " + files[i].getName());
byte[] buffer = new byte[1024];
FileInputStream fis = new FileInputStream(files[i]);
zos.putNextEntry(new ZipEntry(files[i].getName()));
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
}
zos.close();
} catch (IOException ioe) {
Log.e("", ioe.getMessage());
}
}
Also you can use this library to zip a folder or file.
Import the .jar into your project and then you can do this to transform what you need:
try {
File input = new File("path/to/your/input/fileOrFolder");
String destinationPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "zippedItem.zip";
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_STORE);
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
File output = new File(destinationPath);
ZipFile zipFile = new ZipFile(output);
// .addFolder or .addFile depending on your input
if (sourceFile.isDirectory())
zipFile.addFolder(input, parameters);
else
zipFile.addFile(input, parameters);
// Your input file/directory has been zipped at this point and you
// can access it as a normal file using the following line of code
File zippedFile = zipFile.getFile();
} catch (ZipException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
This should do the trick.
I am trying to set a .wav file as a ringtone on Android devices. The code below is able to create directories, and the sound file, but seems to have issues actually setting the file as a ringtone, let alone the selected ringtone. After the method ends, I go to ringtones on the device, and the selected ringtone defaults to "None". Any idea what's going on here? I am using the WRITE_EXTERNAL_STORAGE permission in my manifest. Also, the format of the sound bite doesn't matter to me, I don't mind converting anything that needs converted.
Thanks!!
private String saveAs(String fileName) {
int resSound = getContext().getResources().getIdentifier(fileName, "raw", getContext().getPackageName());
// Resolve save path and ensure we can read and write to it
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/media/audio/ringtones/";
File dir = new File(path);
fileName += ".wav";
if (!dir.exists()) {
dir.mkdirs();
}
if(!dir.canRead() || !dir.canWrite()) {
return "Unable to save ringtone.";
}
// Load the audio into a buffer
byte[] buffer;
InputStream fIn = this.context.getBaseContext().getResources().openRawResource(resSound);
int size;
try {
size = fIn.available();
buffer = new byte[size];
fIn.read(buffer);
fIn.close();
}
catch (IOException e) {
return "Error opening sound file";
}
File file = new File(dir, fileName);
FileOutputStream save;
try {
save = new FileOutputStream(file);
save.write(buffer);
save.flush();
save.close();
}
catch (FileNotFoundException e) {
return "Error loading sound file.";
}
catch (IOException e) {
return "Unable to save ringtone.";
}
// Register the sound byte with the OS and set its properties
this.context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path + fileName)));
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
values.put(MediaStore.MediaColumns.TITLE, getSoundTitle(fileName));
values.put(MediaStore.MediaColumns.SIZE, size);
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/*");
values.put(MediaStore.Audio.Media.ARTIST, "Sound Clip");
values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
values.put(MediaStore.Audio.Media.IS_ALARM, false);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
//Insert it into the database
Uri uri = this.context.getContentResolver().insert(MediaStore.Audio.Media.getContentUriForPath(file.getAbsolutePath()), values);
RingtoneManager.setActualDefaultRingtoneUri(this.context, RingtoneManager.TYPE_RINGTONE, uri);
return "Successfully set ringtone.";
}
For anyone else who runs into this, I figured it out. It's this line.
this.context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path + fileName)));
If anyone happens to know why this is, I'd be very interested to know. Thanks!
So I am working on an Android app and what I am trying to do is make it so a user selects a zip file, it extracts the contents of it into an apk and installs the modified APK for the user. Right now all the files in the zip file have to be in the root of the zip file for it to work, if there is a directory and than the files I need it will not work. I am trying to make it scan for, for example the 'assets' folder and than get the directory its located in and copy all the files from that directory. I've tried extracting the files first and scanning using a loop, and for some reason had no success doing that, and it was time consuming anyways. If you know any libraries or could point me in the right direction that would be great! Thanks!
BTW you can extract all the files from zip folder like below. i.e
private String unpackZip(String path, String zipname) {
String apkfilename = "";
InputStream is;
ZipInputStream zis;
try {
String filename;
is = new FileInputStream(path + "/" + zipname);
zis = new ZipInputStream(new BufferedInputStream(is));
ZipEntry ze;
byte[] buffer = new byte[1024];
int count;
while ((ze = zis.getNextEntry()) != null) {
filename = ze.getName();
// Need to create directories if not exists, or
// it will generate an Exception...
if (ze.isDirectory()) {
File fmd = new File(path + "/" + filename);
fmd.mkdirs();
continue;
}
// This condition is to only extract the apk file
if (filename.endsWith(".apk")) {
apkfilename = filename;
FileOutputStream fout = new FileOutputStream(path + "/"
+ filename);
while ((count = zis.read(buffer)) != -1) {
fout.write(buffer, 0, count);
}
fout.close();
zis.closeEntry();
}
}
zis.close();
} catch (IOException e) {
e.printStackTrace();
return apkfilename;
}
return apkfilename;
}
//To install the apk file call the method
String apkfilename=unpackZip(Environment.getExternalStorageDirectory()
.getPath(), "temp.zip");
try {
File file = new File(Environment.getExternalStorageDirectory()
.getPath(), apkfilename);
Intent promptInstall = new Intent(Intent.ACTION_VIEW).setDataAndType(
Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(promptInstall);
} catch (Exception e) {
e.printStackTrace();
}
//Also add the read write permission
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
i have below code that work in some phone and dont work in some other phone.
my code is for saving an image.
String path = Environment.getExternalStorageDirectory().toString();
path += "/";
File fff=new File(path + "/xalopex/Mobile/");
if (!fff.exists())
fff.mkdirs();
path += "xalopex/Mobile/";
path += "lg";
File filename;
try {
filename = new File(path + ".jpg");
FileOutputStream out = new FileOutputStream(filename);
MyImageBitMap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
MediaStore.Images.Media.insertImage(getContentResolver(),
filename.getAbsolutePath(), filename.getName(),
filename.getName());
} catch (Exception e) {
e.printStackTrace();
//this part will run
// e is storage/emulated/0/xalopex/Mobile/lg.jpg open faild:ENOENT (no such file or directory)
}
where i am wrong ?
How i can fix it?
I would hazard a guess and say its because you need to be accessing /storage/emulated/legacy instead of /storage/emulated/0
I could be wrong.. but I see there are no accepted answers so I'll give this a try :)