So I have an app which downloads certain files, dedicated to a client of mine who is hosting his files on a remote location, and i'm doing so using the code below:
public class DownloadService extends IntentService {
private int result = Activity.RESULT_CANCELED;
public DownloadService() {
super("DownloadService");
}
#Override
protected void onHandleIntent(Intent intent) {
String urlPath = intent.getStringExtra(URL);
String fileName = intent.getStringExtra(FILENAME);
File output = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
fileName);
if (output.exists()) {
output.delete();
}
URLConnection streamConnection = null;
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
streamConnection = url.openConnection();
stream = streamConnection.getInputStream();
streamConnection.connect();
long lengthofFile = streamConnection.getContentLength();
InputStream reader = stream;
bis = new BufferedInputStream(reader);
fos = new FileOutputStream(output.getPath());
int next = -1;
int progress = 0;
int bytesRead = 0;
byte buffer[] = new byte[1024];
while ((bytesRead = bis.read(buffer)) > 0) {
fos.write(buffer, 0, bytesRead);
progress += bytesRead;
int progressUpdate = (int)((progress * 100) / lengthofFile);
Intent testIntent = new Intent(".MESSAGE_INTENT");
testIntent.putExtra(PERCENTAGE, progressUpdate);
sendBroadcast(testIntent);
}
result = Activity.RESULT_OK;
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
publishResults(output.getAbsolutePath(), result);
}
private void publishResults(String outputPath, int result) {
Intent intent = new Intent(".MESSAGE_INTENT");
intent.putExtra(FILEPATH, outputPath);
intent.putExtra(RESULT, result);
sendBroadcast(intent);
}
}
and to call this service i would use:
Intent intent = new Intent(MainActivity.getAppContext(), DownloadService.class);
intent.putExtra(DownloadService.FILENAME, downloadFileName[item]);
intent.putExtra(DownloadService.URL, urlDownload[item]);
MainActivity.getAppContext().startService(intent);
now this allows user to download one file at a time, however if the user downloads another file, the second file will have to wait till the first file is done downloading.
now what is happening in my case is:
1- First download FILE_1 is downloading, and in the status is says FILE_1.
2- User clicks a new file download, the status changes the first file name to the second file name, and waits till FILE_1 finishes download to start with FILE_2 however the active download is changed from FILE_1 to FILE_2.
questions:
is there a way to call DownloadService multiple times for multiple files?
is it possible to fix the problem i'm facing? treating download intent services as two different intents?
UPDATE
I managed to solve this issue by assigning a unique Int ID per file, each ID will point to a position in the listview which displays the files being downloaded or queued, then i work with each file on it's own.
Following code uses commons-io-2.4.jar library to make your work easy by handling low level data movements as you would focus on method in hand
URL someUrl = new URL("your url String"); //
File someFile = new File("your file, where you want to save the data");
FileUtils.copyURLToFile(someUrl, someFile );
if you want to call this statement few time to download different files from the server following code might give you an idea what you might want to do, but you will have to write it's equivalent code to run in android which you want to probably AsyncTask
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.io.FileUtils;
public class DownloadTest {
public static void main(String[] args) {
Thread thread = new Thread(){
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
dowanloadFile(new URL("some url"), new File("some file"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
thread.start();
}
private static void dowanloadFile(URL url, File file){
try {
FileUtils.copyURLToFile(url, file );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Related
I have referred many sites, none of them worked for me to check if download was completed 100%
Scenario- I am downloading a file, and I want my selenium/Java program to wait until the download is completed 100%.
(Downloading through HTTP would be the best, but I did not find anything appropriate that would help me out)
Thanks in Advance!!
The below code worked for me,
There are 2 ways:
1st Method:(You need to download AsyncHttpClient JAR)
try {
AsyncHttpClient client = Dsl.asyncHttpClient();
final FileOutputStream stream = new FileOutputStream(FILE_NAME);
client.prepareGet(FILE_URL).execute(new AsyncCompletionHandler<FileOutputStream>() {
#Override
public State onBodyPartReceived(HttpResponseBodyPart bodyPart)
throws Exception {
stream.getChannel().write(bodyPart.getBodyByteBuffer());
return State.CONTINUE;
}
#Override
public FileOutputStream onCompleted(Response response)
throws Exception {
return stream;
}
});
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
2nd Method :
private static void startDownload(String FILE_URL, String FILE_NAME)
{
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) {
System.out.println(e);
}
}
I know this has been asked a few times here, but I'm not sure which way I should go. This code downloads the html file okay, but I get an IOException when trying to write the html to a file. I've tried many suggestions on sof, but none seem to work for me and I'm at a loss as it seems it should be working.
class Downloader extends AsyncTask<URL, Void, Void> {
String site = getResources().getString(R.string.sched_hd_url);
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File(sdCard.getAbsolutePath() + "/directory/");
File file = new File(dir, "file.html");
#Override
protected Void doInBackground(URL... urls) {
try {
URL url = new URL(site);
URLConnection yc = url.openConnection();
BufferedInputStream in = new BufferedInputStream(new URL(site).openStream());
OutputStream out = new FileOutputStream(file);
int total = 0;
int count;
byte data1[] = new byte[1024];
while ((count = in.read(data1)) != -1) {
out.write(data1);
total += count;
}
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void result) {
progress.setVisibility(View.INVISIBLE);
finish();
}
}
I run this code and no file appears in the directory that I specified. The directory already exists, and I do have the permissions in my manifest. Any suggestions would be greatly appreciated.
So my problem was a couple of things. First, I want to thank those that commented. In my question, I did neglect to put in the out.close(); method. When that didn't work, I was looking at the string which held the URL I wanted to use. That had errors in it. This fixed the download problem, but I wanted to download from a place where the .html file was not in the URL (example: http://www.example.com/ instead of http://www.example.com/index.html). It worked for the latter but not the former. So instead of using URLConnection I used HttpURLConnection. Here is my working code:
class Downloader extends AsyncTask<URL, Void, Void> {
String site = getResources().getString(R.string.sched_hd_url);
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File(sdCard.getAbsolutePath() + "/directory/");
File file = new File(dir, "file.html");
#Override
protected Void doInBackground(URL... uri) {
FileOutputStream out = null;
if (file.exists()) {
try {
file.delete();
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
URL url = new URL(site);
HttpURLConnection yc = (HttpURLConnection) url.openConnection();
BufferedInputStream in = new BufferedInputStream(
new URL(site).openStream());
out = new FileOutputStream(file);
int total = 0;
int count;
byte data1[] = new byte[1024];
while ((count = in.read(data1)) != -1) {
out.write(data1);
total += count;
}
in.close();
out.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void result) {
progress.setVisibility(View.INVISIBLE);
finish();
}
}
Also another error in my question was in regards to no implementation checking to see if the file had already existed. Thanks again for the help.
i've an activity with a button and a label.
On button click my app must download several files ( about 9000 ).
If user clicks again on button, the download must stop and on another click it must start from the beginning.
So this is what i do:
In activity:
file.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Button b = (Button)v;
if(canFile){
b.setText("Stop download");
changeLabelInfo("Getting file list...");
labelFile.setVisibility(View.VISIBLE);
fileTask.start();
}else{
b.setText("Download files");
if(fileTask.isAlive()){
fileTask.interrupt();
fileTask = null;
fileTask = new UpdateFilesThread(this);
}
labelFile.setVisibility(View.INVISIBLE);
Kernel.setManualUpdate("file",false);
}
canFile = !canFile;
}
});
The thread that must download files is UpdateFilesThread:
public class UpdateFilesThread extends Thread{
private MainActivity activity;
private final String rootPath = "/mnt/local/";
public UpdateFilesThread(MainActivity activity){
this.activity = activity;
}
public void run(){
String json = getFilesURL();
JSONObject a = (JSONObject)JSONValue.parse(json);
boolean isZip = false,canDownload = true;
String[] keys = new String[]{"key1","key2","key3","key4"};
for(String key:keys){
Object folder = (Object)a.get(key);
if(folder instanceof JSONObject){
JSONObject fold = (JSONObject)folder;
for(Object path_o:fold.keySet()){
path = path_o.toString().replace(" ", "%20");
if(local.endsWith(".php")){
isZip = true;
try {
Jsoup.connect(mywebserviceURL).data("path",path).timeout(0).post(); // If php generate zip containing php file
} catch (IOException e) {
canDownload = false;
}
}
if(canDownload){
try{
if(downloadFromUrl(path,isZip))
//SAVE URL DOWNLOADED
}catch(Exception e){
e.printStackTrace();
}
}
canDownload = true;
isZip = false;
}
}
}
a.remove(key);
}
private String getFilesURL(){
try {
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("type", new StringBody("all"));
HttpPost post = new HttpPost("mywebserviceURL");
post.setEntity(entity);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(post);
return EntityUtils.toString(response.getEntity());
} catch (UnsupportedEncodingException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (ClientProtocolException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (ParseException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (IOException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
}
}
public boolean downloadFromUrl(String path,boolean isZip){
InputStream is = null;
FileOutputStream fos = null;
String localFilename = rootPath+path;
String local = isZip?rootPath+"tmp.zip":localFilename;
boolean return_ = false;
try {
URL url = new URL(isZip?mywebserviceURLZip:mywebserviceURLZip+path);
URLConnection urlConn = url.openConnection();
urlConn.setReadTimeout(0);
is = urlConn.getInputStream();
fos = new FileOutputStream(local);
byte[] buffer = new byte[51200];
int len;
while ((len = is.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
is.close();
if(isZip){
ZipFile zip = new ZipFile(local);
zip.extractAll(rootPath);
new File(local).delete();
}
return_= true;
}catch(Exception e){
e.printStackTrace();
return false;
}
return return_;
}
}
My problem borns when user clicks two time the button ( stop downloading and start again ).
The prompt error says that the thread is already startend and in running.. how can i solve it? I know that asyncTask should be better but i've problem cause in my application there are so many thread running and the device is so poorly peforming..
It's possible to stop definitelly a thread? are there other better solution?
Try implementing an AsyncTask. When the user first taps the button call the task's execute (Params... params). On the second tap call the task's cancel (boolean mayInterruptIfRunning). Put the download functionality in the task's doInBackground (Params... params)
Your run thread needs to occasionally check isInterrupted() and exit if it returns true. Otherwise the thread will never be canceled.
I think your entire architecture is wrong though. Downloading 9000 files onto a mobile phone? Even if each file is only 1KB, that's a huge amount of memory for a mobile app. And at the very least you ought to zip up that data and download a zip, for your own sanity.
I have code:
private MediaRecorder recorder;
String hostname = "192.168.1.125";
int port = 1935;
Socket socket;
ParcelFileDescriptor pfd;
public void start()
{
try {
socket = new Socket(InetAddress.getByName(hostname), port);
pfd = ParcelFileDescriptor.fromSocket(socket);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
recorder.setOutputFile(pfd.getFileDescriptor());
// String filename = String.format("/sdcard/%d.mp4", System.currentTimeMillis());
//
// recorder.setOutputFile(filename);
try
{
recorder.prepare();
recorder.start();
}
catch (IllegalStateException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
And Server side:
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args)
{
try
{
System.out.println("create sock");
ServerSocket svsock = new ServerSocket(1935);
System.out.println("accept");
Socket sock = svsock.accept();
System.out.println("buffer read");
FileOutputStream outFile = null;
String filename = String.format("%d.mp4", System.currentTimeMillis());
try {
outFile = new FileOutputStream(filename);
System.out.println(filename);
} catch (IOException e1) {
e1.printStackTrace();
}
InputStream is = new DataInputStream(sock.getInputStream());
byte[] byteBuffer = new byte[1024];
int allsize = 0;
while(sock.isConnected()) {
int size = is.read(byteBuffer);
if (size == -1){
break;
} else {
outFile.write(byteBuffer, 0, size);
}
allsize += size;
}
System.out.println("close size=" + allsize);
outFile.close();
sock.close();
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("endmain");
}
}
I test it on Android 2.2.2 (HTC quiet brilliant) and all works fine. When I press "start" button Server create file and record data from stream to file. After this file is normally play in VLC player and etc.
But when I test it on Android 4.0.4 (Galaxy S2) Server create file and record data from stream to file but not play in VLC (and other players too) and give me error
mp4 error: MP4 plugin discarded (no moov,foov,moof box)
avcodec error: Could not open �codec demux error: Specified event object handle is invalid
ps error: cannot peek
main error: no suitable demux module for `file/:///C:/1345461283455.mp4'
I also try to upload this file to youtube, but after upload youtube give me error like file format is unsupported.
But Android 4.0.4 (Galaxy S2) succesfully create and then play file when I save it on phone memory (not stream to server)
I think problem maybe on server side, or something changed on android 4.0.4.
Please, help me.
Thanks in advance.
try this
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setOutputFile(pfd.getFileDescriptor());
I think it should solve the problem. Give it a try and see if it helps ...
I am downloading files from the internet and saving the streaming data to a temp file in my app's internal storage given by getFilesDir().
Once the download is complete, I need to move the temp file to my download directory on External Memory (usually an SD Card). For some reason though, File.renameTo() isn't working for this. I'm guessing there's a problem because it's two separate file systems, but I can still download directly to the SD Card and the file URIs are correct.
Is there another simple and quick way to transfer that file from internal memory to external or do I have to do a byte stream copy and delete the original?
To copy files from internal memory to SD card and vice-versa using following piece of code:
public static void copyFile(File src, File dst) throws IOException
{
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try
{
inChannel.transferTo(0, inChannel.size(), outChannel);
}
finally
{
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
}
And - it works...
Internal and external memory is two different file systems. Therefore renameTo() fails.
You will have to copy the file and delete the original
After you copy the file (as #barmaley's great answer shows), don't forget to expose it to the device's gallery, so the user can view it later.
The reason why it has to be done manually is that
Android runs a full media scan only on reboot and when (re)mounting
the SD card
(as this guide shows).
The easier way to do this is by sending a broadcast for the scanning to be invoked:
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(outputFile));
context.sendBroadcast(intent);
And voila! You can now view your file in the device's gallery.
An alternative to the copying using your own function is to use Apache's library's class "FileUtils" , in the function called copyFile :
FileUtils.copyFile(src, dst, true);
Did some trivial modifications to #barmaley's code
public boolean copyFile(File src, File dst) {
boolean returnValue = true;
FileChannel inChannel = null, outChannel = null;
try {
inChannel = new FileInputStream(src).getChannel();
outChannel = new FileOutputStream(dst).getChannel();
} catch (FileNotFoundException fnfe) {
Log.d(logtag, "inChannel/outChannel FileNotFoundException");
fnfe.printStackTrace();
return false;
}
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
} catch (IllegalArgumentException iae) {
Log.d(logtag, "TransferTo IllegalArgumentException");
iae.printStackTrace();
returnValue = false;
} catch (NonReadableChannelException nrce) {
Log.d(logtag, "TransferTo NonReadableChannelException");
nrce.printStackTrace();
returnValue = false;
} catch (NonWritableChannelException nwce) {
Log.d(logtag, "TransferTo NonWritableChannelException");
nwce.printStackTrace();
returnValue = false;
} catch (ClosedByInterruptException cie) {
Log.d(logtag, "TransferTo ClosedByInterruptException");
cie.printStackTrace();
returnValue = false;
} catch (AsynchronousCloseException ace) {
Log.d(logtag, "TransferTo AsynchronousCloseException");
ace.printStackTrace();
returnValue = false;
} catch (ClosedChannelException cce) {
Log.d(logtag, "TransferTo ClosedChannelException");
cce.printStackTrace();
returnValue = false;
} catch (IOException ioe) {
Log.d(logtag, "TransferTo IOException");
ioe.printStackTrace();
returnValue = false;
} finally {
if (inChannel != null)
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
if (outChannel != null)
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return returnValue;
}
Picture that:
This is internal path : pathInternal
And this is external path :
pathExternal
Try with this code:
public void moveIn (String pathInternal, String pathExternal) {
File fInternal = new File (pathInternal);
File fExternal = new File (pathExternal);
if (fInternal.exists()) {
fInternal.renameTo(fExternal);
}
}
You can do it using operations with byte[]
define in your class:
public static final String DATA_PATH =
Environment.getExternalStorageDirectory().toString() + "/MyAppName/";
then:
AssetManager assetManager = context.getAssets();
InputStream in = assetManager.open("data/file.txt");
OutputStream out = new FileOutputStream(DATA_PATH + "data/file.txt");
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
For Move file best way is Renaming it's path with different path and name
example:
File from = new File(Environment.getExternalStorage().getAbsolutePath()+"/kaic1/imagem.jpg");
File to = new File(Environment.getExternalStorage().getAbsolutePath()+"/kaic2/imagem.jpg");
from.renameTo(to);