How to detect "half-downloaded" files in Java/Android - java

I'm trying to handle the download of some files in my app. Basically I download a file when needed and show it to the user.
I also want to seize the downloaded files as cache, so I use a hash over the url and when the map collides with an existing file I consider it a cache hit.
My pseudo code is:
String filename = hash(url);
File outputFile = new File(cacheFolder,filename);
if(!outputFile.exists()){
download(url,outputFile);
}
return outputFile;
The code I'm using to download the file from the url is;
URL url = new URL(urlToDownload);
URLConnection connection = url.openConnection();
connection.connect();
// this will be useful so that you can show a typical 0-100% progress bar
int fileLength = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(connection.getInputStream());
OutputStream output = new FileOutputStream(outputFile.getAbsolutePath());
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
It works nice but I have a problem for detecting the following case:
The app starts downloading a file, while partially written, the user kills the app, leaving the output file in a inconsistent state.
The user reopens the app, I detect the file exists but I can't detect the file is corrupt, so I try to open the file, failing.
How can I solve this?
Should I download in a temp file and copy it to the outputFile while completed? Or this could cause a unnecessary overhead.
Is there some way to avoid the file to be created until the download is finished without using the temporally file+copy approach?
Thanks

Related

Android AsyncTask downloading .mp3 file - info and thumbnail

I am trying to download a mp3 file from a server.
I successfully made it, and I can play the file, but there is no thumbnail and file info, such as artist and album names.
When I'm downloading the file directly from chrome, the information I stated above, DOES get downloaded.
Any ideas how to get it work?
Here is my code:
URL url = new URL(urlDwn+urlVid);
HttpURLConnection connection =(HttpURLConnection) url.openConnection();
connection.connect();
//file length
int lengthOfFile = connection.getContentLength();
//intput - read file
InputStream inputStream = new BufferedInputStream(url.openStream(), 8192);
//output - write file
if(true) {
System.out.println("Downloading");
OutputStream outputStream = new FileOutputStream(root+"/"+fileName);
System.out.println(root+"/"+fileName);
byte data[] = new byte[1024];
long total = 0;
while ((count = inputStream.read(data)) != -1) {
total += count;
//progress
publishProgress((int) ((total * 100) / lengthOfFile));
//writing to file
outputStream.write(data,0, count);
}
outputStream.flush();
outputStream.close();
inputStream.close();
I SOLVED IT!
it seems that the thumbnail and mp3 tag(artist and etc) were downloaded properly. the problem was in the file manager itself(or maybe the Android system), so when I restarted the device, it shown itself!
EDIT
There is no need to reboot. All you need to do is to add the lines below to the onPostExecute method, which tell the system that a new file has been added.
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
sendBroadcast(intent);

Java - Monitor progress of a async file downloading in server

I have a server-side application which download file from an external URL into the server. This happens on an async process. I will need to have a Ajax call to get the file download progress and report in UI.
This can be achieved by updating the file download progress into a DB in a defined interval and AJAX call can get progress from Database. But this will be DB resource intensive.
Another option (I'm not sure if this works) is to read the file downloading in progress to compare the size with the total Content-Length to get the % downloaded.
Is there any way to access the OutputStream from the async background process and return the upload % ?
The front end of the application is using AngularJS and backend is implemented using Spring Framework.
File Download code is generic:
// opens input stream from the HTTP connection
InputStream inputStream = httpConn.getInputStream();
String saveFilePath = saveDir + File.separator + fileName;
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
int bytesRead = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();

Java : download file outside server context

I need to save a file and download file in directory outside server context.
I am using Apache Tomacat
I am able to do this in directory present in webapps directory of application
If my directory structure is as follows,
--src
--WebContent
-- uploaddir
-- myfile.txt
Then I am able to download in by simply.
download
But, problem is when file is in some other directory say d:\\uploadedfile\\myfile.txt
then I wont be able to download it, as resource is not in server context as above.
I have file path to uuid mapping,
like,
d:\\uploadedfiles\\myfile.txt <-> some_uuid
then I want file should be downloaded, on click of following,
download
So, How to make file downloadable when it is outside the server context,
I heard about getResourceAsStream() method which would do this , But would any one help me on how to do this, probably with simple code snippet?
Try the below code which you can write in filedownloadservet. Fetch the file name from the request parameter and then read and write the file.
If you need to do some security checks then do that before processing the request.
File file = new File("/home/files", "file name which user wants to download");
response.setContentType(getServletContext().getMimeType(file.getName()));
response.setContentLength(file.length());
BufferedInputStream inputStream = null;
BufferedOutputStream outputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(file));
outputStream = new BufferedOutputStream(response.getOutputStream());
byte[] buf = new byte[2048];
int len;
while ((len = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, len);
}
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
//log it
}
}
// do the same for input stream also
}
here i found the answer,
response.setContentType("application/msword");
response.setHeader("Content-Disposition","attachment;filename=downloadname.doc");
File file=new File("d:\\test.doc");
InputStream is=new FileInputStream(file);
int read=0;
byte[] bytes = new byte[BYTES_DOWNLOAD];
OutputStream os = response.getOutputStream();
while((read = is.read(bytes))!= -1){
os.write(bytes, 0, read);
}
os.flush();
os.close();
Base path will not work that is for HTML and it works if the base path is also exposed by your web server which does not look like case here.
To download an arbitary file you need to open the file using a FileInputStream (and surround it by a buffered input stream), read a byte, then send that byte from your servlet to the client.
Then there are security concerns, so should google that (basically not give access to any file but only file that is to be shared, audit download etc as needed.
Again in your servlet set the mime type etc and then open a input stream and write the bytes to the output stream to client

Still An Issue? - java.util.zip.ZipException: Central Directory Entry not found

As a disclaimer, I've already seen this post and the posts linking to it.
I have a file hosted on a server that is n archived file and I am trying to unarchive it using this method. When the file is pre-downloaded to the device and I open and unarchive it in my application, through an intent-filter from Downloads, there isn't any problem. However, when I download it from the server within my application, then try to unzip it, I get the error in the title on this line:
ZipFile zipfile = new ZipFile(archive);
Where archive is a File pointing to the archive file I downloaded. The code I'm using to download the archive is as follows:
String urlPath = parameters[0], localPath = parameters[1];
try
{
URL url = new URL(urlPath);
URLConnection connection = url.openConnection();
connection.addRequestProperty("Accept-Encoding", "gzip");
connection.connect();
int fileLength = connection.getContentLength();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new BufferedOutputStream(new FileOutputStream(localPath));
byte data[] = new byte[1024];
long total = 0;
int count;
while((count = input.read(data)) != -1)
{
total += count;
publishProgress((int)total * 100 / fileLength);
output.write(data);
}
output.flush();
output.close();
input.close();
I've recently added the encoding type as-per the post I referenced at the top, but I am still getting the same error. Any help would be great.
Just to clarify:
I have an archive file
It unarchives fine when the file was downloaded externally and opened/unarchived inside my app
When I download the archive and then try to unarchive it, I receive the error java.util.zip.ZipException: Central Directory Entry not found
My best guess is that this is a problem with my download. However, that being said, I don't know what I'm doing wrong.
You aren't copying the download correctly. You must use
output.write(data, 0, count);
Otherwise you are writing arbitrary junk into the file.

Java + Google Web Toolkit (google apps engine) download file from server

I have deployed an application in Google App Engine and and I want to upload and download data from server using java code at desktop and server code for download request and one more: Where do I store the data in apps engine?
To store binary data (file contents) you have three options:
Blob property of Datastore entities
Blobstore
Google Cloud Storage
You can save your file anywhere on your server, you just need to know the path.
how i direct it as output stream?
Here is a code snippet that can help you.
File fileOnServer = new File("Hello.txt"); // Give full path where your file is located
byte[] file = new byte[(int) fileOnServer.length()];
FileInputStream fileInputStream = new FileInputStream(fileOnServer);
fileInputStream.read(file);
int contentLength = (int) file.length;
response.setContentLength(contentLength);
response.setHeader("Content-Disposition", "attachment; filename=\"Hello.txt\"");
out = response.getOutputStream();
int bytesWritten = 0;
byte[] buffer = new byte[1024];
while (bytesWritten < contentLength) {
int bytes = Math.min(1024, contentLength - bytesWritten);
System.arraycopy(file, bytesWritten, buffer, 0, bytes);
if (bytes > 0) {
out.write(buffer, 0, bytes);
bytesWritten += bytes;
} else if (bytes < 0);
}
get download to user end?
Well you can add ClickHandler on a Button on your client side and override onClick method.
public void onClick(ClickEvent event) {
Window.open("UrlToYourServelet", "_blank", "null");
}
Hope this helps!
EDIT
I have found a solution. You can upload the file at any free file hosting site like this. This site provides a URL for every uploaded file. So in your servelet, make a HTTP request to the URL and download the file in byte[] and write it on outputStream as shown in the code above.

Categories