Sending Large file over network/localhost - android

Here's the code:
private void sendFile(InputStream file, OutputStream out) throws IOException {
Log.d(TAG, "trying to send file...");
final int buffer_size = 4096;
try {
byte[] bytes = new byte[buffer_size];
while(true) {
int count = file.read(bytes, 0, buffer_size);
if (count == -1) {
break;
}
out.write(bytes, 0, count);
Log.d("copystream", bytes + "");
}
} catch (Exception e) {
Log.e("copystream", "exception caught while sending file... " + e.getMessage());
}
}
I'm trying to send a large File (InputStream file) over an output stream (OutputStream out). This code works for smaller files, but for something like 5mb and above (I haven't benchmarked the limit), it just freezes after sometime without error or anything.
Log.d("copystream", bytes + ""); would output for some time, but will eventually stop logging.
Log.e("copystream", "exception caught while sending file... " + e.getMessage()); never shows.
This is part of a larger codebase which is actually a file server that runs on the Android device.
Any ideas?

Here's what made it work:
while (true) {
synchronized (buffer) {
int amountRead = file.read(buffer);
if (amountRead == -1) {
break;
}
out.write(buffer, 0, amountRead);
}
}

Use Multipart POST. Something like
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null,null);
entity.addPart("File", new FileBody (new File(FILE_PATH), MIME_TYPE));
httppost.setEntity(entity);
HttpResponse response = httpclient.execute(httppost);
return response;

Use AsyncTask Class for this, here is link for example
http://developer.android.com/reference/android/os/AsyncTask.html

Related

Android unable to successfully convert HTTP image/jpeg response to Bitmap

I am sending images from a server script using image/jpeg type response. Here is the server code (php using CodeIgniter):
$file = file_get_contents("http://www.menucool.com/slider/prod/image-slider-5.jpg");
$this->output->set_header("Content-Type: image/jpeg; charset=UTF-8");
$this->output->set_header("HTTP/1.1 200 OK");
$this->output->set_header("Accept-Charset", "utf-8");
$this->output->set_header("Accept-Encoding", "");
$this->output->set_output($file);
And this script sends the image to android, where I try to decode using the following script:
Log.e("response",response);
try {
String decompressedResponse = decompress(response.getBytes("UTF-8"));
InputStream instream = new ByteArrayInputStream(decompressedResponse.getBytes("UTF-8"));
Log.e("inputstream",instream.toString());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
try {
while ((len = instream.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
} catch (IOException e) {
}
byte[] b = baos.toByteArray();
Log.e("bytearray",b.toString());
imageBitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
image.setImageBitmap(imageBitmap);
} catch (UnsupportedEncodingException e) {
Log.e("UnsupportedEcondingEception","UNSUPPORTEDENCODINGEXCEPTIOn");
} catch (IOException e1) {
return;
}
Logcatting the response shows characters like this:
���8�#
The really weird thing here is that if I call this script from a web browser, it displays the image but apparently android and eclipse cannot decode this encoding.
I think it is an android problem rather than the server's. Any suggestions, hints are really appreciated as I have been stuck for a while.

Android Large File Upload as Byte Array to Restful WCF Service giving Bad Request

I am facing problem while trying to upload a zip file containing images converted into byte array to a restful wcf service from a json client using HTTPPost. The byte array is encoded into BASE64 enclosed into JSON object and sent using StringEntity with 2 more parameters. Around 6KB of file gets uploaded without any flaws but file more than 6KB are not send and I get a Bad Request - 400 status code. Following code is used to upload the file:
File file = new File(dir, "file.zip");
byte[] buf = new byte[10240000];
fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (int readNum; (readNum = fis.read(buf)) != -1;) {
bos.write(buf, 0, readNum);
Log.v("read : buf ", buf + " : " + readNum + " bytes");
}
byte[] bytes = bos.toByteArray();
imgData = Base64.encodeToString(bytes, Base64.DEFAULT);
JSONObject sendData=null;
Log.d("Image Data length", imgData.length()+"");
Log.d("Image data ", imgData);
try {
sendData= new JSONObject();
sendData.put("_binaryData", imgData);
sendData.put("_fileName", "fileName");
sendData.put("userid", userID);
int len = imgData.length();
int l=sendData.toString().length();
entity = new StringEntity(sendData.toString());
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Send request
int len = imgData.length();
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
request.setHeader("Connection", "Keep-Alive");
request.setParams(httpParameters);
DefaultHttpClient httpClient = new DefaultHttpClient();
request.setEntity(entity);
HttpResponse response = httpClient.execute(request);
HttpEntity responseEntity = response.getEntity();
String str=response.getStatusLine().getReasonPhrase();
int i=response.getStatusLine().getStatusCode();
Log.v("ReasonPhrase :: StatusCode",str+" "+i);
int contentLength = (int) responseEntity.getContentLength();
char[] buffer = new char[(int) responseEntity
.getContentLength()];
InputStream stream = responseEntity.getContent();
Please help me in solving this.
If a message with <6k bytes does through, but messages with >6k don't, I'd take a look at the client and host limits for things like:
MaxBufferSize
MaxBufferPoolSize
MaxReceivedMessageSize
You don't say whether or not you have control over the host server settings, but you can increase and decrease the limits on items like those mentioned earlier. You can set them to Integer.Max if necessary, a size that would allow file uploads > 1 GB.

My file downloader occur error suddenly

#Override
public void run() {
URL imgurl;
int Read;
try {
imgurl = new URL(ServerUrl);
HttpURLConnection conn = (HttpURLConnection) imgurl.openConnection();
int len = conn.getContentLength();
Log.d("check", "ContentLength:" + len);
Log.d("check", "ServerUrl:" + ServerUrl);
Log.d("check", "LocalPath:" + LocalPath);
byte[] tmpByte = new byte[len];
InputStream is = conn.getInputStream();
File file = new File(LocalPath);
FileOutputStream fos = new FileOutputStream(file);
for (;;) {
Read = is.read(tmpByte);
if (Read <= 0) {
break;
}
fos.write(tmpByte, 0, Read);
}
is.close();
fos.flush();
fos.close();
conn.disconnect();
} catch (MalformedURLException e) {
ut.CalltoAlertDialog_ok(getString(R.string.alert), getString(R.string.setting_skin_downloadfail));
} catch (IOException e) {
ut.CalltoAlertDialog_ok(getString(R.string.alert), getString(R.string.setting_skin_downloadfail));
}
mAfterDown.sendEmptyMessage(0);
}
This is file download source.
This code prints error "NegativeArraySizeException" from here
byte[] tmpByte = new byte[len];
So, I checked len's value.
len's value was -1.
But..
When i created yesterday, This code was not print error.
I have 2 apk file.
The apk created yesterday is not a problem. Even now this apk is no problem.
But, The apk created today is problem.
I did not modify anything.
What is the cause of this?
I think your problem is here:
HttpURLConnection conn = (HttpURLConnection) imgurl.openConnection();
int len = conn.getContentLength();
Read documentation about the getContentLength method
Returns the content length in bytes specified by the response header
field content-length or -1 if this field is not set.
Returns the value of the response header field content-length.
So this case that getContentLength returned -1 seems to have happened to you. Then you use this -1 to set your Array size. => Exception thrown
Check the solution of this question about getContentLength returning -1, maybe you will have to do something similar.
But at least you will have to check that len > 0 before setting your array size

Downloading big video file giving out of memory error

I have used intent service to download a set video files, but while downloading some big size videos it is giving out of memory error in this part "byte[] responseBody = client.execute(getMethod, responseHandler);", I know byte array exceeds the size allotted heap for an app.
I am looking for some alternative solution to overcome this issue, please suggest me if you have some good fix.
#Override
public void onHandleIntent(Intent i) {
Log.d("gl", "onhandleintent");
HttpGet getMethod = new HttpGet(i.getData().toString());
int result = Activity.RESULT_CANCELED;
ad_id =i.getStringExtra("ad_id");
try {
ResponseHandler<byte[]> responseHandler = new ByteArrayResponseHandler();
byte[] responseBody = client.execute(getMethod, responseHandler);
Log.d("gl", "file name " + i.getData().getLastPathSegment());
File output = new File(SharedPreferenceClass.readName(
Downloader.this, "videoFolder", "itaxi-videos"), i
.getData().getLastPathSegment());
if (output.exists()) {
output.delete();
}
FileOutputStream fos = new FileOutputStream(output.getPath());
fos.write(responseBody);
fos.close();
result = Activity.RESULT_OK;
} catch (IOException e2) {
Log.e(getClass().getName(), "Exception in download", e2);
result = Activity.RESULT_CANCELED;
}
Bundle extras = i.getExtras();
// sending back datas to the handle for further updations like db
if (extras != null) {
Messenger messenger = (Messenger) extras.get(EXTRA_MESSENGER);
Message msg = Message.obtain();
msg.arg1 = result;
try {
Bundle bundle = new Bundle();
bundle.putString("ad_id", ad_id);
msg.setData(bundle);
messenger.send(msg);
} catch (android.os.RemoteException e1) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
}
Thanks in advance
The problem is this: You are using a ResponseHandler that simply reads the entire HTTP response into a byte array in memory. You don't have that much memory.
You need to get the underlying InputStream and loop, reading a reasonable amount of data from the stream then writing to your output file.
The InputStream is inside the HttpEntity which you get from the HttpResponse
You can either:
A) Write a custom ResponseHandler whose constructor you pass your File to and it does all the work.
or
B) Just call client.execute(getMethod). This will return the HttpResponse directly.

InputStream won't close, or takes forever to

I'm attempting to download an external mp3 into internal storage. However, the files I'm attempting to download are big, so I'm trying to download them in 1MB chunks so that you can begin playing them while the rest is downloaded. Here's my stream code:
InputStream is = null;
OutputStream os = null;
try {
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet( url );
HttpResponse response = client.execute( get );
MyLog.d( "Connection established" );
byte[] buffer = new byte[8192];
is = new BufferedInputStream( response.getEntity().getContent(), buffer.length );
os = openFileOutput( filename, MODE_PRIVATE );
int size;
int totalSize = 0;
while (( size = is.read( buffer ) ) != -1 && totalSize < 1048576) {
os.write( buffer, 0, size );
totalSize += size;
}
MyLog.d( "Finished downloading mix - " + totalSize + " bytes" );
}
catch (ClientProtocolException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if ( os != null ) {
try {
os.flush();
os.close();
}
catch (IOException e) {
MyLog.e( "Failed to close output stream." );
}
}
if ( is != null ) {
try {
is.close();
}
catch (IOException e) {
MyLog.e( "Failed to close input stream." );
}
}
}
It downloads the file fine, but when it gets to is.close() in the finally statement, it hangs. If I wait a really long time it'll eventually close. It seems like it's still downloading the rest of the file. How do I avoid this and close the stream immediately?
With HTTP, You normally still have to read (and throw away) the whole rest of the response stream - you cannot just close. The entire stream must be consumed. I am not sure if Android's httpclient is based on commons httpclient 3 or 4 - with 4 you can use HttpUriRequest#abort() to end early. Not sure if 3 has such an option
Edit: Looked it up and it looks like httpclient 3 , and you can do httpget.abort()

Categories

Resources