I am trying to copy a large pdf-file (3.7 mb) from my raw-folder to the external cache directory.
I a using the following piece of code:
int i = 0;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
InputStream input = getResources().openRawResource(pdfs[i]);
File file = new File(Environment.getExternalStorageDirectory(), "/Android/data/eu.app/cache/" + pdfNames[i]);
if(!file.exists())
{
try
{
new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/eu.app/cache").mkdirs();
FileOutputStream fos = new FileOutputStream(file.toURI().getPath(), false);
OutputStream os = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int byteRead = 0;
while ((byteRead = input.read(buffer)) != -1) {
os.write(buffer, 0, byteRead);
}
fos.close();
}
catch(Exception ex)
{
Log.d("storage", ex.getMessage());
}
}
}
else
{
}
I don't get any errors, but the output-file is a few bytes smaller than the original and cannot be opened.
What do I need to do to fix this?
I think the main issue is that you close fos while you should close os. You also need to put the close operation in a finally block.
Update (now with a full keyboard ;)): You close the file stream (fos) before the buffered stream is flushed. What you should do is to close the buffered stream (os), and that will in turn flush its buffer and write those bytes that are missing, and then it will automatically close the underlying file stream. To fix it change fos.close() into os.close().
In addition, to make sure that you always close the stream you should place the close operation in a finally block. A typical pattern is the following:
BufferedInputStream in = null;
try {
in = new BufferedInputStream(anInputStream);
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(aFile));
// Read and write what you should write
}
finally {
if (out != null) out.close();
}
} finally {
if (in != null) in.close();
}
You can easily add an input stream, but be careful to make sure all streams are closed. This can be handled by nesting finally blocks or nesting try-catch blocks inside the finally block.
Either you throw an IOException from this method and handle it outside (often preferred), or you wrap the above code in a new try-catch statement and handle it there. However, handling it within the method mixes UI with logic and the code is often clearer separating UI and logic.
A final note: 1024 is rather small. Play with different values. On the other hand the buffered stream will handle the buffering for you.
I've been using this function for reading from one stream to another for a few years and have never had any problems with the resulting file. Just open the source and target files as you are and pass their respective streams into this function:
public static void streamToStream(InputStream is, OutputStream os) {
int count = 0;
try {
while(count != -1) {
byte[] bytes = new byte[2048];
count = is.read(bytes);
if(count == -1) {
continue;
}
os.write(bytes, 0, count);
bytes = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
Related
I'm trying to convert this image url to file object :
https://graph.facebook.com/v4.0/10211842143528384/picture?height=200&width=200&migration_overrides=%7Boctober_2012%3Atrue%7D
this link came from the facebook response after i logged in.
i used this method to convert this image url to File object:
URL url = null;
try {
url = new URL(sharePreferences.getPreferencesProfilePicture());
} catch (MalformedURLException e) {
e.printStackTrace();
}
File f = new File(url.getFile());
Log.d("CHECKER",""+f.exists());
Log.d("CHECKER",""+f.length());
but when i check it's length, its just 0 and the file exist is false.
You have a file with length 0 because you are just creating it with the name of the result of url.getFile(), url.getFile() returns a string which corresponds to the fetched file name.So you end up with a file named picture:
https://graph.facebook.com/v4.0/10211842143528384/picture?height=200&width=200&migration_overrides=%7Boctober_2012%3Atrue%7 But what about the contents? you have to download them fron the internet as a stream and feed that stream into a file. There many ways of doing that with plain Java. A basic copy-paste from https://www.baeldung.com/java-download-file
try (BufferedInputStream in = new BufferedInputStream(new URL(FILE_URL).openStream());
FileOutputStream fileOutputStream new FileOutputStream(FILE_NAME)) {
byte dataBuffer[] = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
} catch (IOException e) {
// handle exception
}
Since you are using android I would strongly encourage you to use fully featured Network libraries such as OkHttp3, Retrofit or Volley, but guessing your knowledge I think you will do better learning the basics on Java then jump to the mentioned libraries.
Remember, for android you need the INTERNET permission to access the internet, then if you download into a file on the external storage you would also need the EXTERNAL_STORAGE permission. Snippet for android:
try {
URLConnection conection = url.openConnection();
conection.connect();
int lenghtOfFile = conection.getContentLength();
// Read from the Network stream
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(Environment
.getExternalStorageDirectory().toString()
+ "/downloaded.png");
byte data[] = new byte[1024];
while ((count = input.read(data)) != -1) {
total += count;
// Feed the bytes read from the input stream into our output stream
output.write(data, 0, count);
}
// Flushing the out stream.
output.flush();
// closing streams
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
This snippet does networking stuff so you need to run it on a background thread. I hope my answer helps you, if not, let me know what else can I do for you.
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've been looking at this site for the past 3 or so hours. How to copy files from 'assets' folder to sdcard?
This is the best I could come up with because I'm only trying to copy one file at a time.
InputStream in = null;
OutputStream out = null;
public void copyAssets() {
try {
in = getAssets().open("aabbccdd.mp3");
File outFile = new File(root.getAbsolutePath() + "/testf0lder");
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: ", 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've figured out how to create a file and save a text file. http://eagle.phys.utk.edu/guidry/android/writeSD.html
I would rather save an mp3 file to the sdcard rather than a text file.
When I use this code I provided, I get a text document that same size as the aabbccdd.mp3 file. It does not create a folder and save an .mp3 file. It saves a text document in the root folder. When you open it, I see a whole bunch of chinese letters, but at the top in English I can see the words WireTap. WireTap Pro was the program I used to record the sound so I know the .mp3 is passing through. It's just not creating a folder and then saving a file like the above .edu example.
What should I do?
I think you should do something like that -[Note: this i used for some other formats not mp3 but its works on my app for multiple format so i hope it will work for u too.]
InputStream in = this.getAssets().open("tmp.mp3"); //give path as per ur app
byte[] data = getByteData(in);
Make sure u have the folder already exists on path, if folder is not there it will not save content correctly.
byteArrayToFile(data , "testfolder/tmp.mp3"); //as per ur sdcard path, modify it.
Now the methods ::
1) getByteData from inputstream -
private byte[] getByteData(InputStream is)
{
byte[] buffer= new byte[1024]; /* or some other number */
int numRead;
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try{
while((numRead = is.read(buffer)) > 0) {
bytes.write(buffer, 0, numRead);
}
return bytes.toByteArray();
}
catch(Exception e)
{ e.printStackTrace(); }
return new byte[0];
}
2) byteArrayToFile
public void byteArrayToFile(byte[] byteArray, String outFilePath){
FileOutputStream fos;
try {
fos = new FileOutputStream(outFilePath);
fos.write(byteArray);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I tried to create a RandomAccessFile object from a raw resource file in android resource directory without success.
I'm only able to get a inputstream object from raw resource file.
getResources().openRawResource(R.raw.file);
Is it possible to create a RandomAccessFile object from raw asset file or Do I need to stick with inputstream?
It's simply not possible to seek forward and back in an input stream without buffering everything in between into memory. That can be extremely costly, and isn't a scalable solution for reading a (binary) file of some arbitrary size.
You're right: ideally, one would use a RandomAccessFile, but reading from the resources provides an input stream instead. The suggestion mentioned in the comments above is to use the input stream to write the file to the SD card, and randomly access the file from there. You could consider writing the file to a temporary directory, reading it, and deleting it after use:
String file = "your_binary_file.bin";
AssetFileDescriptor afd = null;
FileInputStream fis = null;
File tmpFile = null;
RandomAccessFile raf = null;
try {
afd = context.getAssets().openFd(file);
long len = afd.getLength();
fis = afd.createInputStream();
// We'll create a file in the application's cache directory
File dir = context.getCacheDir();
dir.mkdirs();
tmpFile = new File(dir, file);
if (tmpFile.exists()) {
// Delete the temporary file if it already exists
tmpFile.delete();
}
FileOutputStream fos = null;
try {
// Write the asset file to the temporary location
fos = new FileOutputStream(tmpFile);
byte[] buffer = new byte[1024];
int bufferLen;
while ((bufferLen = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bufferLen);
}
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {}
}
}
// Read the newly created file
raf = new RandomAccessFile(tmpFile, "r");
// Read your file here
} catch (IOException e) {
Log.e(TAG, "Failed reading asset", e);
} finally {
if (raf != null) {
try {
raf.close();
} catch (IOException e) {}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {}
}
if (afd != null) {
try {
afd.close();
} catch (IOException e) {}
}
// Clean up
if (tmpFile != null) {
tmpFile.delete();
}
}
Why not get a new AssetFileDescriptor each time you need a seek? It seems not to be a cpu cycles intensive task (or is it?)
//seek to your first start position
InputStream ins = getAssets().openFd("your_file_name").createInputStream();
isChunk.skip(start);
//read some bytes
ins.read(toThisBuffer, 0, length);
//later on
//seek to a different position, need to openFd again!
//because createInputStream can be called on asset file descriptor only once.
//This resets the new stream to file offset 0,
//so need to seek (skip()) to a new position relative to file beginning.
ins = getAssets().openFd("your_file_name").createInputStream();
ins.skip(start2);
//read some bytes
ins.read(toThatBuffer, 0, length);
I've used this method in my app that needs random access to a 20Mb resource file hundreds of times per second.
I am trying to read a response from a server and transform it from InputStream to String but something goes wrong and i cannot see right now why.
InputStream is = entity.getContent();
FileOutputStream folder = new FileOutputStream(
Environment.getExternalStorageDirectory()
+ "/test.xml");
try {
byte[] buf = new byte[1048576];
int current = 0;
int newCurrent = 0;
while ((current = is.read(buf)) != -1) {
newCurrent = newCurrent + current;
folder.write(buf, 0, current);
}
System.out.println("returned folder" + folder);
folder.flush();
} catch (IOException e) {
System.out.println("error on reading input: " + e.getMessage());
}
This is the error:
error on reading input: Socket closed
This is the error I get and another problem that i don't understand is why it does not read the entire content from InputStream(maybe because it's all in one line?).
Thanks.
you dont need to read entire stream in one shot and put it in a byte array, in fact you read it in parts through while loop and put the contents in file stream gradually:
int count;
byte[] filebytes = new byte[1024];
while((count = is.read(filebytes)) != -1){
folder.write(filebytes, 0, count); //writing buffer into file
}
in.close();
folder.flush();
folder.close();
According to stacktrace your crash happens in readLine() while your code uses is.read(buf).
DO these match together?