Why is it not working?
Edit: added new versions of code & logs:
private void savePhotoFromCacheToFolder(Uri uri) {
File goodPhoto = album.setUpPhotoFile(); //new empty JPG
File currentPhoto = new File(uri.getPath()); //JPG from camera in cache
Log.v(TAG, "\ngoodPhoto Path " + goodPhoto);
Log.v(TAG, "\ncurrentPhoto Path " + currentPhoto);
FileInputStream source = null;
FileOutputStream destination = null;
try {
source = new FileInputStream(currentPhoto);
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.v(TAG, "\ncurrentPhoto not found ");
}
try {
destination = new FileOutputStream(goodPhoto);
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.v(TAG, "\ngoodPhoto not found ");
}
FileChannel sourceFileChannel = source.getChannel();
FileChannel destinationFileChannel = destination.getChannel();
long size = 0;
try {
size = sourceFileChannel.size();
sourceFileChannel.transferTo(0, size, destinationFileChannel);
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "\nshit happens ");
}
}
Logs:
V/MainActivity: goodPhoto Path /storage/emulated/0/Pictures/Good photos/IMG_20170222_113700_-913025224.jpg
V/MainActivity: currentPhoto Path /cache/photo.jpg
V/MainActivity: currentPhoto not found
java.lang.NullPointerException: Attempt to invoke virtual method 'java.nio.channels.FileChannel java.io.FileInputStream.getChannel()' on a null object reference
It looks like Uri is not correct, but this Uri was returned by Camera app. Or maybe I have no access to cache folder, but earlier I did preview photo using this Uri.
we have created an input stream and an output stream object. The input stream points to the current java file and the output stream is pointing to Output.java. It is to this Output.java we want the contents of the file to be transferred. As mentioned earlier, a file object is associated with a File Channel object. So, we obtain the File Channel object for both the input and the output stream using the following code,
public copyFile( String filePath ){
FileInputStream source = new FileInputStream(filePath );
FileOutputStream destination = new FileOutputStream("Output.java");
FileChannel sourceFileChannel = source.getChannel();
FileChannel destinationFileChannel = destination.getChannel();
long size = sourceFileChannel.size();
sourceFileChannel.transferTo(0, size, destinationFileChannel);
}
Compare your code with above code , there is difference of method for transferring data and while is not used here.
Related
I am trying to save data into text file in the internal storage and read it again .. It works fine in my mobile with android 11 but when i tried at android 8 it gives me this error
java.io.FileNotFoundException:/data/user/0/com.example.example/test.txt
(No such file or directory)
It appears at the first time to open the activity but i can clear it - as normal text - and write a new text and save it so the file is there and usable
here is read code
File path = getApplicationContext().getFilesDir();
File readFrom = new File(path, fileName);
byte[] content = new byte[(int) readFrom.length()];
try {
FileInputStream stream = new FileInputStream(readFrom);
stream.read(content);
return new String(content);
} catch (Exception e) {
e.printStackTrace();
return e.toString();
}
and this write code
public void writeToFile(String fileName, String content) {
File path = getApplicationContext().getFilesDir();
try {
FileOutputStream writer = new FileOutputStream(new File(path, fileName));
writer.write(content.getBytes());
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I need to get a File from DocumentFile or Uri with correct scheme not the one with content://com.android.externalstorage.documents/tree/primary: if the device's main memory is selected.
To get File or absolute path of the image i need the one with file:///storage/emulated/0 or storage/emulated/0 but i could not find a way to get correct Uri for building a File to write EXIF data to image.
My scenario is:
User chooses a path to save images which returns Uri with content://com.android.externalstorage.documents onActivityResult(). I save this path with treeUri.toString() to SharedPreferences for using later.
User takes a picture and image is saved with DocumentFile.fromTreeUri(MainActivity.this, Uri.parse(uriString));
This where i fail, getting a File that correctly points to image, Uri with content:// does not return the existing image.Correct Uri should file:///storage/emulated/ and i can convert this Uri to file using File filePath = new File(URI.create(saveDir.getUri().toString()));
How can i get the Uri needed for consturcting File or File using Uri i got from SAF UI?
EDIT: ExifInterface Support Library is introduced for Android 7.1+ that can use InputStream or FileDescriptor.
Uri uri; // the URI you've received from the other app
InputStream in;
try {
in = getContentResolver().openInputStream(uri);
ExifInterface exifInterface = new ExifInterface(in);
// Now you can extract any Exif tag you want
// Assuming the image is a JPEG or supported raw format
} catch (IOException e) {
// Handle any errors
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignored) {}
}
}
Note: ExifInterface will not work with remote InputStreams, such as those returned from a HttpURLConnection. It is strongly recommended to only use them with content:// or file:// URIs.
Snippet above is reading data obviously since it opens an InputStream to read data. I need to be able to write EXIF data to JPEG files.
Answer for writing Exif data to an image previously saved and with known content Uri using FileDescriptor if Api is 24 or above
private void writeEXIFWithFileDescriptor(Uri uri) {
if (Build.VERSION.SDK_INT < 24) {
showToast("writeEXIFWithInputStream() API LOWER 24", Toast.LENGTH_SHORT);
return;
}
ParcelFileDescriptor parcelFileDescriptor = null;
try {
parcelFileDescriptor = mContext.getContentResolver().openFileDescriptor(uri, "rw");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
showToast("writeEXIFWithFileDescriptor(): " + fileDescriptor.toString(), Toast.LENGTH_LONG);
ExifInterface exifInterface = new ExifInterface(fileDescriptor);
// TODO Create Exif Tags class to save Exif data
exifInterface.saveAttributes();
} catch (FileNotFoundException e) {
showToast("File Not Found " + e.getMessage(), Toast.LENGTH_LONG);
} catch (IOException e) {
// Handle any errors
e.printStackTrace();
showToast("IOEXception " + e.getMessage(), Toast.LENGTH_LONG);
} finally {
if (parcelFileDescriptor != null) {
try {
parcelFileDescriptor.close();
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
}
}
If Api is lower than 24 it's necessary to use a buffer file and save that buffer file to actual location with DocumentFile after writing Exif data is finished.
private boolean exportImageWithEXIF(Bitmap bitmap, DocumentFile documentFile) {
OutputStream outputStream = null;
File bufFile = new File(Environment.getExternalStorageDirectory(), "buffer.jpg");
long freeSpace = Environment.getExternalStorageDirectory().getFreeSpace() / 1048576;
double bitmapSize = bitmap.getAllocationByteCount() / 1048576d;
showToast("exportImageWithEXIF() freeSpace " + freeSpace, Toast.LENGTH_LONG);
showToast("exportImageWithEXIF() bitmap size " + bitmapSize, Toast.LENGTH_LONG);
try {
outputStream = new FileOutputStream(bufFile);
// Compress image from bitmap with JPEG extension
if (mCameraSettings.getImageFormat().equals(Constants.IMAGE_FORMAT_JPEG)) {
isImageSaved = bitmap.compress(CompressFormat.JPEG, mCameraSettings.getImageQuality(), outputStream);
showToast("isImageSaved: " + isImageSaved, Toast.LENGTH_SHORT);
}
if (isImageSaved) {
writeEXIFWithFile(bufFile);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
OutputStream os = null;
InputStream is = null;
try {
int len;
byte[] buf = new byte[4096];
os = mContext.getContentResolver().openOutputStream(documentFile.getUri());
is = new FileInputStream(bufFile);
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
os.close();
is.close();
if (bufFile != null) {
bufFile.delete();
bufFile = null;
}
} catch (IOException e) {
e.printStackTrace();
}
return isImageSaved;
}
Both methods can be used to write Exif data to image saved to device's memory or SD card. You can also save image to SD card using valid Uri from Storage Access Framework.
I also found a way to get absolute path for memory and SD card from content Uri but it's irrelevant for this question and using Uri instead of absolute path is encouraged and does not lead to unnoticed errors, i also wasn't able to save image to SD card with absolute path, only able to read from it.
I'm working on a test app to integrate soundtouch (an open source audio processing library) on Android.
My test app already can receive input from the mic, pass the audio thru soundtouch and output the processed audio to an AudioTrack instance.
My question is, how can I change the output from AudioTrack to a new File on my device?
Here's the relevant code in my app (where I'm processing the output of soundtouch, into the input for AudioTrack)
// the following code is a stripped down version of my code
// in no way its supposed to compile or work. Its here for reference purposes
// pre-conditions
// parameters - input : byte[]
soundTouchJNIInstance.putButes(input);
int bytesReceived = soundTouchJNIInstance.getBytes(input);
audioTrackInstance.write(input, 0, bytesReceived);
Any ideas on how to approach this problem? Thanks!
Hope you are already getting the input voice from microphone and saved on a file.
Firstly, import JNI libraries to your oncreate method :
System.loadLibrary("soundtouch");
System.loadLibrary("soundstretch");
Soundstrech library :
public class AndroidJNI extends SoundStretch{
public final static SoundStretch soundStretch = new SoundStretch();
}
Now you need to call soundstrech.process with the input file path and the desired output file to store processed voice as parameters :
AndroidJNI.soundStretch.process(dataPath + "inputFile.wav", dataPath + "outputFile.wav", tempo, pitch, rate);
File sound = new File(dataPath + "outputFile.wav");
File sound2 = new File(dataPath + "inputFile.wav");
Uri soundUri = Uri.fromFile(sound);
The soundUri can be provided as a source to media player for play back :
MediaPlayer mediaPlayer = MediaPlayer.create(this, soundUri);
mediaPlayer.start();
Also note that, the sample size for recording should be selected dynamically by declaring an Array of Sample Rates :
int[] sampleRates = { 44100, 22050, 11025, 8000 }
The best way to write byteArray this :
public void writeToFile(byte[] array)
{
try
{
String path = "Your path.mp3";
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream stream = new FileOutputStream(path);
stream.write(array);
} catch (FileNotFoundException e1)
{
e1.printStackTrace();
}
}
I am not aware of sound touch at all and the link i am providing no where deals with jni code, but you can have a look at it if it helps you any way: http://i-liger.com/article/android-wav-audio-recording
I think the best way to achieve this is converting that audio to a byte[] array. Assuming you have already done that (if not, comment it and I'll provide an example), the above code should work. This assumes you're saving it in a external sdcard in a new directory called AudioRecording and saving it as audiofile.mp3.
final File soundFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "AudioRecording/");
soundFile.mkdirs();
final File outFile = new File(soundFile, 'audiofile.mp3');
try {
final FileOutputStream output = new FileOutputStream(outFile);
output.write(yourByteArrayWithYourAudioFileConverted);
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mkdirs() method will try to construct all the parent directories if they're missing. So if you're planning to store in a 2 or more level depth directory, this will create all the structure.
I use a simple test code snippet to write my audio byte arrays:
public void saveAudio(byte[] array, string pathAndName)
{
FileOutputStream stream = new FileOutputStream(pathAndName);
try {
stream.write(array);
} finally {
stream.close();
}
}
You will probably need to add some exception handling if you are going to be using this in a production environment, but I utilise the above to save audio whenever I am am in the development phase or for personal non-release projects.
Addendum
After some brief thought I have changed my snippet to the following slightly more robust format:
public void saveAudio(byte[] array, string pathAndName)
{
try (FileOutputStream stream= new FileOutputStream(pathAndName)) {
stream.write(array);
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
stream.close();
}
}
You can use the method using SequenceInputStream, in my app I just merge MP3 files in one and play it using the JNI Library MPG123, but I tested the file using MediaPlayer without problems.
This code isn't the best, but it works...
private void mergeSongs(File mergedFile,File...mp3Files){
FileInputStream fisToFinal = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mergedFile);
fisToFinal = new FileInputStream(mergedFile);
for(File mp3File:mp3Files){
if(!mp3File.exists())
continue;
FileInputStream fisSong = new FileInputStream(mp3File);
SequenceInputStream sis = new SequenceInputStream(fisToFinal, fisSong);
byte[] buf = new byte[1024];
try {
for (int readNum; (readNum = fisSong.read(buf)) != -1;)
fos.write(buf, 0, readNum);
} finally {
if(fisSong!=null){
fisSong.close();
}
if(sis!=null){
sis.close();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(fos!=null){
fos.flush();
fos.close();
}
if(fisToFinal!=null){
fisToFinal.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have a method in a second class (Class2) where I pass in the values of context and uri from Class1. The second class (Class2) is a class where filters will be applied to images taken using the camera from Class1. The method in Class2 looks something like this
public void prepareImage(Context context, Uri uri) {
// BitmapFactory options
Options options = new Options();
options.inSampleSize = 2;
String path = uri.toString();
File file = new File(path);
FileInputStream fis = null; //initialize
try {
fis = new FileInputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Bitmap img = BitmapFactory.decodeStream(fis);
Log.i(TAG, "Bitmap img: " + img);
//more code below, but above this comment is where the issue is
}
I am noticing that FileInputStream is returning null, therefore BitmapFactory.decodeStream is decoding nothing. There are two things that I think are issues but am not sure how to address them. First, I was wondering if I am receiving null for FileInputStream because I am using a path that is formed from uri.toString(). Or does that matter? The string path value is correct.
The second issue is that if my phone is tethered to the computer, after taking an image using my application, the image file does not seem to register until after I unplug the device from my computer. Only after I unplug my device from the computer does all my images come up in the gallery folder. So my suspicion is that file is not being found! There is evidence of this from logcat.
Anyway, I do not know how to get around this conflict. Maybe I need to save images in a different way. Here is how I am saving images in Class1.
File imgFileDir = getDir();
if (!imgFileDir.exists() && !imgFileDir.mkdirs()) {
Log.e(TAG, "Directory does not exist");
}
//Locale.US to get local formatting
SimpleDateFormat timeFormat = new SimpleDateFormat("hhmmss", Locale.US);
SimpleDateFormat dateFormat = new SimpleDateFormat("ddMMyyyy", Locale.US);
String time = timeFormat.format(new Date());
String date = dateFormat.format(new Date());
String photoFile = date + "_nameofapp_" + time + ".jpg";
String filename = imgFileDir.getPath() + File.separator + photoFile;
File pictureFile = new File(filename);
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(arg0);
fos.flush();
fos.close();
} catch (Exception e) {
Log.e(TAG, "Image could not be saved");
e.printStackTrace();
}
I also use a helper method
private File getDir() {
File sdDir = Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return new File(sdDir, "NameOfApp");
}
Lastly, I tried running the application untethered to my computer to see if it would work and it does not. The behavior is just the same, images that I take picture of does not show up in the gallery until I replug the device to my computer, and then all the images I took show up in the gallery. Why?
Per request, I am passing the URI from Class1 doing the following.
Class2 classTwo = new Class2();
classTwo.prepareImage(this, uri);
Just moving this to an answer so everyone can see:
It looks like an extra / got into your file Uri.
file:/storage/emulated/0 ...
versus
/file:/storage/emulated/0 ... (from the exception message)
:)
I have a layout where I have an Edit Text field where I enter my data.
I have 2 buttons.Save and Plot.
When I press save I want to save the data (in xls format) from edittext field and the current date in sd card.
When I press the plot ,I want to plot them.
To save data:
case R.id.savebtn:
savefunc();
break;
...
public void savefunc(){
//saving
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard, "MyFiles");
directory.mkdirs();
File file = new File(directory, filename);
try {
FileOutputStream fOut = new FileOutputStream(file);
DataOutputStream os = new DataOutputStream(fOut);
os.writeUTF(thedata);
os.writeUTF(mydate);
os.close();
} catch (FileNotFoundException e) {
// handle exception
} catch (IOException e) {
// handle exception
}
}
For reading:
public void readfunc(){
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard, "MyFiles");
File file = new File(directory, filename);
try{
FileInputStream fIn = new FileInputStream(file);
DataInputStream is = new DataInputStream(fIn);
String name = is.readUTF();
String content = is.readUTF();
is.close();
} catch (FileNotFoundException e) {
// handle exception
} catch (IOException e) {
// handle exception
}
}
and :
case R.id.savebtn:
savefunc();
break;
case R.id.graphicsbtn:
readfunc();
...
But the xls file asks me format , I choose UTF8 and it is empty.
If I leave it shows chinese characters.
I am not sure about the "reading" part of the code.
Read this documentation here have more information about save data to external storage and read it is:
Saving and Reading file from External storage
Ok, I found this and works fine!