I'm putting together some code to download files from an HTTP address in Android. I'd like to support download resumption if the download fails mid way.
The output I get when starting the download, then killing the wifi connection and restarting again several times is the following:
Start size 0
Stop size 12333416
Start size 12333416
Stop size 16058200
Start size 3724784
I cannot understand why after the first resumption, subsequent file size readings of the partially downloaded file do not match.
Thanks in advance!
public void download(String source, String target) throws IOException {
BufferedOutputStream outputStream = null;
InputStream inputStream = null;
try {
File targetFile = new File(target);
currentBytes = targetFile.length();
Log.i(TAG, "Start size " + String.valueOf(currentBytes));
outputStream = new BufferedOutputStream(new FileOutputStream(targetFile));
// create the input stream
URLConnection connection = (new URL(source)).openConnection();
connection.setConnectTimeout(mCoTimeout);
connection.setReadTimeout(mSoTimeout);
inputStream = connection.getInputStream();
inputStream.skip(currentBytes);
// calculate the total bytes
totalBytes = connection.getContentLength();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) > 0) {
// write the bytes to file
outputStream.write(buffer, 0, bytesRead);
outputStream.flush();
currentBytes += bytesRead;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
// close the output stream
outputStream.flush();
outputStream.close();
}
if (inputStream != null) {
// close the input stream
inputStream.close();
}
Log.i(TAG, "Stop size " + String.valueOf(currentBytes));
}
}
There are two things you are doing wrong:
To resume download to file you should append, not rewrite the file. Use special constructor for output stream:
FileOutputStream(targetFile, true)
To request part of file from server you should use HTTP 1.1 property "Range". You can do it like this:
HttpURLConnection httpConnection = (HttpURLConnection) connection;
connection.setRequestProperty("Range", "bytes=" + currentBytes + "-");
Related
Problem: My File not Launching which is requested from sever.
Okay I have written a server/client application but the problem is when i request for a file from the server it transfer over to the client but what I have notice is that I need to manually refresh the directory to get the file to be in the path or directory. So by saying that, I feel that this is why my code when request the file it doesn't launch.
My approach launching the file from the client after it had just been requested.
Here is my code below:
public static void receiveFile(String fileName) {
try {
int bytesRead;
InputStream in = sock.getInputStream();
DataInputStream clientData = new DataInputStream(in);
fileName = clientData.readUTF();
OutputStream output = new FileOutputStream((fileName));//need to state a repository
long size = clientData.readLong();
byte[] buffer = new byte[1024];
while (size > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
output.close();
in.close();
File file = new File(fileName);
Desktop.getDesktop().open(file);
//System.out.println("File "+fileName+" received from Server.");
} catch (IOException ex) {
//Logger.getLogger(CLIENTConnection.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
}
Please can you look are tell me what you think I am doing wrong?
Server code:
Try flush the stream before close.
output.flush();
output.close();
I solve it my self the answer is to use the code below:
replace: Desktop.getDesktop().open(file);
with: Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + file);
I am sending files to remote Android client from java server. I write the bytes using outputstream. On reading these bytes read() method keep trying to read bytes after the stream is ended. if I close the outputstream on server-side, read operation work fines. But I have to write file on the same socket again so can't close output stream any solution?
NOTE: MY CODE WORKS FINE FOR SHARING SINGLE FILE
CODE FOR WRITING FILE
public static void writefile(String IP, String filepath, int port, OutputStream out) throws IOException {
ByteFileConversion bfc = new ByteFileConversion();
byte[] file = bfc.FileToByteConversion(filepath);
out.write(file, 0, file.length);
out.close(); // i donot want to close this and how can I tell reading side that stream is ended.
System.out.println("WRITTEN");
}
Here Am I reading the file on Android :
public Bitmap fileReceived(InputStream is) {
Bitmap bitmap = null;
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "a.png";
String imageInSD = baseDir + File.separator + fileName;
// System.out.println(imageInSD);
if (is != null) {
FileOutputStream fos = null;
OutputStream bos = null;
try {
bos = new FileOutputStream(imageInSD);
byte[] aByte = new byte[1024];
int bytesRead;
int index = 0;
DataInputStream dis = new DataInputStream(is);
while ((bytesRead = is.read(aByte)) > 0) {
index = bytesRead + index;
bos.write(aByte, 0, bytesRead);
// index = index+ bytesRead;
System.out.println("Loop" + aByte + " byte read are " + bytesRead + "whree index =" + index);
}
bos.flush();
bos.close();
Log.i("IMSERVICE", "out of loop");
java.io.FileInputStream in = new FileInputStream(imageInSD);
bitmap = BitmapFactory.decodeStream(in);
bitmap = BitmapFactory.decodeFile(imageInSD);
Log.i("IMSERVICE", "saved");
// if (bitmap != null)
// System.out.println("bitmap is "+ bitmap.toString());
} catch (IOException ex) {
// Do exception handling
// Log.i("IMSERVICE", "exception ");
System.out.println("ex");
}
}
return bitmap;
}
Actually, I want to reset socket connection
Thanks in advance
You need to:
Send the length of the file ahead of the file. You can use DataOutputStream.writeLong() for that, and DataInputStream.readLong() at the receiver.
Read exactly that many bytes from the stream at the receiver:
while (total < length && (count = in.read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total))) > 0)
{
out.write(buffer, 0, count);
total += count;
}
E&OE
Actually I want to reset socket connection
Actually you don't want to do any such thing.
If i donot close outputstream the read operation on other side stuck on keep reading
That is because the client socket's InputStream is still waiting for the server to send some packets of data thus blocking your Main Thread.
Solution:
You can put each of your sending(OutputStream) and reading(InputStream) of packets of data from the socket to a Thread to prevent blocking your main thread when reading and sending.
Create a thread that reads the InputStream and another one for the OutputStream
Side note:
Don't try to close your outputStream that it cant be reopened again as the documentation is saying:
Closing the returned OutputStream will close the associated socket.
The general contract of close is that it closes the output stream. A closed stream cannot perform output operations and cannot be reopened.
My Android app has a Webview to access to my website. I noticed in the server that when a file is downloaded by the app the bandwidth used is less than when is downloaded by another device or browser.
In method onDownloadStart I call to an AsyncTask class:
protected String doInBackground(String... sUrl) {
try {
URL url = new URL(sUrl[0]);
//Getting directory to store the file
//Connection handler
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.connect();
//Obtaining filename
File outputFile = new File(directory, filename);
InputStream input = new BufferedInputStream(connection.getInputStream());
OutputStream output = new FileOutputStream(outputFile);
byte buffer[] = new byte[1024];
int bufferLength = 0;
int total = 0;
while ((bufferLength=input.read(buffer))!=-1) {
total += bufferLength;
output.write(buffer, 0, bufferLength);
}
connection.disconnect();
output.flush();
output.close();
input.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Files downloaded are empty altough their filename and format are correct and I receive HTTP 200 message from the server; also execution does not enter into the while loop. I have tried to change buffer size and the problem is not solved.
I wrote the following code for downloading some files from a server but the problem is that this code isn't reading the complete response (inputStream). File size is 7.5 MB while I am getting 5.5 MB each time and of course adobe reader complains that file is damaged. Here is the code
import java.net.URLConnection;
public class Downloader {
URL url;
public Downloader(){
try {
url = new URL("https://d396qusza40orc.cloudfront.net/algs4partI/slides%2F13StacksAndQueues.pdf");
FileOutputStream outStream;
ObjectOutputStream oStream;
try {
URLConnection con = url.openConnection();
InputStream inStream = con.getInputStream();
outStream = new FileOutputStream("data.pdf");
oStream = new ObjectOutputStream(outStream);
int bytesRead;
int totalBytesRead = 0;
byte[] buffer = new byte[100000];
while((bytesRead = inStream.read(buffer)) > 0){
//outStream.write(buffer, 0 , bytesRead);
oStream.write(buffer, 0, bytesRead);
buffer = new byte[100000];
totalBytesRead += bytesRead;
}
System.out.println("Total Bytes read are = " + totalBytesRead);
oStream.close();
outStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args){
Downloader d = new Downloader();
}
}
Any ideas what I am doing wrong here? Thanks in advance.
You don't want to be using ObjectOutputStream when you aren't serializing java objects.
Un-comment the line
//outStream.write(buffer, 0 , bytesRead);
and remove
oStream.write(buffer, 0, bytesRead);
So:
while((bytesRead = inStream.read(buffer)) > 0){
outStream.write(buffer, 0 , bytesRead);
buffer = new byte[100000]; // this line is useless
totalBytesRead += bytesRead;
}
Get rid of the ObjectOutputStream altogether. Your file is 5.25 MB (5,511,685 bytes) long, not 7.5 MB.
InputStream that you get from URL connection does not guarantee that all bytes arrive at once. They are transfered over network, so your reading speed may be higher than your network. Method read() returns number of bytes that have been read at current execution of the method. If it returns 0 the information is probably not available at the moment but will be available later.
Method read() returns -1 to indicate end of stream. Bottom line: change > 0 in your if statement to >= 0.
The problem is that you are using ObjectOutputStream. This encodes the output in the Java Object Serialization format, which is not what the PDF reader expects / requires.
Use a plain FileOutputStream and it should work.
I got working over socket file sender, it worked perfectly, but I couldn't send large files with it. Always got heap error. Then I changed the code of client, so it would send file in chunks. Now I can send big files, but there is new problem. Now I recieve small files empty and larger files for example videos can't be played. Here is the code of client that sends file:
public void send(File file) throws UnknownHostException, IOException {
// Create socket
hostIP = "localhost";
socket = new Socket(hostIP, 22333);
//Send file
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
OutputStream os = socket.getOutputStream();
//Sending size of file.
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(file.getName() + ":" + userName);
byte[] arr = new byte[1024];
try {
int len = 0;
while ((len = dis.read(arr)) != -1) {
dos.write(arr, 0, len);
}
} catch (IOException ex) {
ex.printStackTrace();
}
dos.flush();
socket.close();
}
and here is the server code:
void start() throws IOException {
// Starts server on port.
serverSocket = new ServerSocket(port);
int bytesRead;
while (true) {
connection = serverSocket.accept();
in = connection.getInputStream();
clientData = new DataInputStream(in);
String[] data = clientData.readUTF().split(":");
String fileName = data[0];
String userName = data[1];
output = new FileOutputStream("C:/" + fileName);
long size = clientData.readLong();
byte[] buffer = new byte[1024];
// Build new file
while (size > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
output.close();
}
}
You failed to write out the length of the file to the stream in the client:
long size = clientData.readLong();
So that call in the server is reading the first 8 bytes of the actual file and who knows what that quantity is. You don't have to read the length from the stream since you only wrote a single file. After reading the filename, and username (not very secure is it?) you can just read the stream until EOF. If you ever wanted to send multiple files over the same open socket then you'd need to know the length before reading the file.
Also your buffers for reading are way to small. You should be at a minimum of 8192 instead of 1024. And you'll want to put all .close() in a finally block to make sure your server and clients shutdown appropriately if there is an exception ever.