The thing is I'm trying to upload an image to a server.
The image has to be uploaded by chunks of 256kb and I need to pass the chunks count and id with every call.
I can get the total number of chunks to upload and I'm using a BufferedInputStream to get the chunks bytes.
But when I finish to upload all the chunks the image showed is always corrupted.
My code so far:
int chunkSize = 255 * 1024;
final long size = mFile.length();
final long chunks = mFile.length() < chunkSize? 1: (mFile.length() / chunkSize);
int chunkId = 0;
BufferedInputStream stream = new BufferedInputStream(new FileInputStream(mFile));
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "RQdzAAihJq7Xp1kjraqf";// random data
for (chunkId = 0; chunkId < chunks; chunkId++) {
URL url = new URL(urlString);
// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(20000 /* milliseconds */);
conn.setConnectTimeout(20000 /* milliseconds */);
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
dos = new DataOutputStream( conn.getOutputStream() );
dos.writeBytes(twoHyphens + boundary + lineEnd);
String param1 = ""+chunkId;
String param2 = ""+chunks;
String param3 = mFile.getName();
// for every param
dos.writeBytes("Content-Disposition: form-data; name=\"chunk\"" + lineEnd);
dos.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dos.writeBytes("Content-Length: " + param1.length() + lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(param1 + lineEnd);
dos.writeBytes(twoHyphens + boundary + lineEnd);
// Send parameter #chunks
dos.writeBytes("Content-Disposition: form-data; name=\"chunks\"" + lineEnd);
dos.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dos.writeBytes("Content-Length: " + param2.length() + lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(param2 + lineEnd);
dos.writeBytes(twoHyphens + boundary + lineEnd);
// Send parameter #name
dos.writeBytes("Content-Disposition: form-data; name=\"name\"" + lineEnd);
dos.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dos.writeBytes("Content-Length: " + param4.length() + lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(param3 + lineEnd);
dos.writeBytes(twoHyphens + boundary + lineEnd);
// Send parameter #file
dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + param4 + "\"" + lineEnd); // filename is the Name of the File to be uploaded
dos.writeBytes("Content-Type: image/jpeg" + lineEnd);
dos.writeBytes(lineEnd);
byte[] buffer = new byte[chunkSize];
stream.skip(chunkId * chunkSize);
stream.read(buffer);
// dos.write(buffer, 0, bufferSize);
dos.write(buffer);
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
dos.flush();
dos.close();
// read response...
}
Many thanks!
Well,
I solved the issue.
I deleted the following line:
stream.skip(chunkId * chunkSize);
I was skipping several chunks of the stream :). Sorry my bad.
You have to define "multipart/form-data" instead of form-data when sending image (file)
Related
I have a custom json request class to upload multi-part files to server this class in an Android application , it works fine when I add English words as keys and values(these keys and values are one part) but when I use any Arabic word, it writes unknown words like "'D*F*9".
Before I write these values to ByteArrayOutputStream object, every thing works fine, and I can see Arabic words.
This is the get Body Content Type method for the all class
#Override
public String getBodyContentType() {
return "multipart/form-data;charset=UTF-8;boundary=" + boundary;
//return "application/json; charset=UTF-8";
//return "multipart/form-data; charset=UTF-8";
}
Here is the build Text Part method to construct the text part
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
//dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
//dataOutputStream.writeBytes("Content-Type: application/json; charset=UTF-8" + lineEnd);
Log.d("inside buildText", parameterName + " " + parameterValue);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
And here the code I have used to debug these values
// just for debugging
DataInputStream in = new DataInputStream(new ByteArrayInputStream (bos.toByteArray()));
Scanner scanner = new Scanner(in);
while (scanner.hasNext()){
Log.d("scanner ", scanner.next());
}
I have read this RFC document but I can't understand what the purpose of Content-Disposition and what does its values mean.
What should I edit in this code to get the Arabic values correctly ?
Should I change the content type in all parts or I can make every part has its content Type ?
Any help plz ?
Finally I found the answer, the problem was in this line
dataOutputStream.writeBytes(parameterValue + lineEnd);
So I updated it to
dataOutputStream.write(parameterValue.getBytes("utf-8"));
dataOutputStream.writeBytes(lineEnd);
to get all un ASCII characters, and now it works fine for all languages.
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
//dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
//dataOutputStream.writeBytes("Content-Type: application/json; charset=UTF-8" + lineEnd);
Log.d("inside buildText", parameterName + " " + parameterValue);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.write(parameterValue.getBytes("utf-8"));
dataOutputStream.writeBytes(lineEnd);
//dataOutputStream.writeBytes(parameterValue + lineEnd);
}
Hello am trying to upload a file from external storage of android phone to the url in the variable upLoadServerUri as below.
final String upLoadServerUri = "http://www.www.com/UploadToServer.php";
URL url = new URL(upLoadServerUri);
// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true); // Allow Inputs
conn.setDoOutput(true); // Allow Outputs
conn.setUseCaches(false); // Don't use a Cached Copy
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("uploaded_file", fileName);
dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\";filename=\""
+ fileName + "\"" + lineEnd);
dos.writeBytes(lineEnd);
// create a buffer of maximum size
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
Log.d("Inside ByteRead", "Reading");
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
serverResponseCode = conn.getResponseCode();
String serverResponseMessage = conn.getResponseMessage();
fileInputStream.close();
dos.flush();
dos.close();
The code below is being used in the UploadToServer.php file which is the destination url file in the java code above. I don't have knowledge on php end so can you advise me if below code would be able to store data when we trigger a file to it based on the java code above. Thanks.
<?php
// Where the file is going to be placed
$target_path = "recorded/";
/* Add the original filename to our target path.
Result is "uploads/filename.extension" */
$target_path = $target_path . basename( $_FILES['uploaded_file']['name']);
if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $target_path)) {
echo "The file ". basename( $_FILES['uploaded_file']['name']).
" has been uploaded";
} else{
echo "There was an error uploading the file, please try again!";
echo "filename: " . basename( $_FILES['uploaded_file']['name']);
echo "target_path: " .$target_path;
}
?>
Please try retrofit. Its simple and easy. Read this tutorial. Upload Files to Server
I am sending files via post method using HttpURLConnection. I am sending with the file a parameter which is 'student_id'. The code is working fine when sending one file in each post request. But, how can I update the code below to send multiple files in one post request where all the files belong to the same 'student_id'?
try{
File textFile2 = new File("info.txt");
URL url = new URL("htttp://wwww.students.com");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setChunkedStreamingMode(0);
urlConnection.setDoOutput(true);
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
urlConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
OutputStream output = urlConnection.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"student_id\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append(CRLF).append("25").append(CRLF).flush();
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"newfile\"; filename=\"" + textFile2.getName() + "\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset!
writer.append(CRLF).flush();
Files.copy(textFile2.toPath(), output);//copies all bytes in a file to the output stream
output.flush(); // Important before continuing with writer!
writer.append(CRLF).flush();
writer.append("--" + boundary + "--").append(CRLF).flush();
InputStream responseStream;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I tried to add 'multiple' with the parameter in 'newfile' but it is not working
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"newfile\" multiple; filename=\"" + textFile2.getName() + "\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset!
writer.append(CRLF).flush();
Files.copy(textFile2.toPath(), output);//copies all bytes in a file to the output stream
output.flush(); // Important before continuing with writer!
writer.append(CRLF).flush();
writer.append("--" + boundary + "--").append(CRLF).flush();
Seems that you are trying to post a multipart/form-data request with 1 form field with name parameter of student_id and multiple file part to upload files.
You can send multiple filesby supplying each file in a separate part but all with the same name parameter.
For example, you can upload a file of textFile1 by sending the first file part with name parameter of newfile:
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"newfile\"; filename=\"" + textFile1.getName()+ "\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
writer.append(CRLF);
writer.flush();
FileInputStream inputStream = new FileInputStream(textFile1);
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
inputStream.close();
writer.append(CRLF);
writer.flush();
Then, you can upload another file of textFile2 by sending file part with same name parameter of newfile:
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"newfile\"; filename=\"" + textFile2.getName()+ "\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
writer.append(CRLF);
writer.flush();
FileInputStream inputStream = new FileInputStream(textFile2);
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
inputStream.close();
writer.append(CRLF);
writer.flush();
As you can see, the code are almost the same except the file to upload. It is recommend to put the code into a method and call it to send each file part.
We are working on uploading image to our server from android device. Image is successfully uploading in server while using both mobile data and Wi-Fi, except one particular network which we are currently using. This new network setup don’t let pass any data from client end which has greater MTU size than 1460. So, all the packets from android device are rejected and cannot reach the server. Our iOS app can upload image to same server successfully with same network. We have found with tracing that iOS reduces the packet or chunk size if one packet is not successfully sent. But android devices are not behaving like that. We have also found that some social networking android apps can successfully upload image with our network. Some would probably say to change our network with correct settings, but we don’t want to do that as if we can have a defective network, some other people can also have that, where our android app will not work properly.
The works we have tried so far (all of which are working, except the new network) are given below:
Main code which we were using from first:
private boolean uploadImage(String fileLoc, String title){
try {
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
URL connectURL;
connectURL = new URL(baseUrlString); // our server url to upload image
FileInputStream fileInputStream = new FileInputStream(fileLoc);
// ------------------ CLIENT REQUEST
// Open a HTTP connection to the URL
HttpURLConnection conn = (HttpURLConnection) connectURL
.openConnection();
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
//conn.setChunkedStreamingMode(512);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
//conn.setFixedLengthStreamingMode(137931);
DataOutputStream dos = new DataOutputStream(
conn.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\""
+ param1 + "\"" + lineEnd
+ lineEnd
+ title
+ lineEnd);
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\""
+ fileLoc
+ "\""
+ lineEnd);
dos.writeBytes(lineEnd);
// create a buffer of maximum size
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
// read file and write it into form...
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// close streams
fileInputStream.close();
dos.flush();
InputStream is = conn.getInputStream();
// retrieve the response from server
int ch;
StringBuffer b = new StringBuffer();
while ((ch = is.read()) != -1) {
b.append((char) ch);
}
String response;
response = b.toString().trim();
dos.close();
// here some work with response
return sucs;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Here we have also tried with
conn.setChunkedStreamingMode(512);
conn.setRequestProperty("Transfer-Encoding", "chunked");
to limit the chunk size, but it is ignored as the documentation says it is only a hint.
We have also tried with
conn.setFixedLengthStreamingMode(calculatedValueOfbytesForSameImage);
but failed.
Then we tried to implement other methods found in the web using Multipart and Socket:
https://stackoverflow.com/a/16529053/1246639
https://stackoverflow.com/a/19188010/1246639
https://stackoverflow.com/a/22803149/1246639
https://groups.google.com/forum/#!msg/android-developers/SZ5MzO6wr6I/Ol4ZL1Au3U0J
All methods working except our network. Have also tried combining Multipart to ByteArrayOutputStream as https://stackoverflow.com/a/10225966/1246639. But still not working.
Is there any other method available to control the chunk size using other class like the InterfaceAddress or native support or if we are missing something in methods tried above? Thanks.....
im new in android dev...
i find this code for upload image to server and its work perfect...
just i add editext in layout and i want post value of that edittext with image to server too
part of my code:
URL url = new URL(upLoadServerUri);
conn = (HttpURLConnection) url.openConnection(); // Open a HTTP connection to the URL
conn.setDoInput(true); // Allow Inputs
conn.setDoOutput(true); // Allow Outputs
conn.setUseCaches(false); // Don't use a Cached Copy
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("uploaded_file", fileName);
dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\";filename=\""+ fileName + "\"" + lineEnd);
dos.writeBytes(lineEnd);
bytesAvailable = fileInputStream.available(); // create a buffer of maximum size
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
int serverResponseCode = conn.getResponseCode();
//String serverResponseMessage = conn.getResponseMessage();
if(serverResponseCode == 200){
runOnUiThread(new Runnable() {
public void run() {
my edittext:
<EditText
android:id="#+id/detail"
android:layout_width="match_parent"
android:layout_height="164dp"
android:layout_gravity="right"
android:layout_marginBottom="15dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:ems="10"
android:hint="About Your picture"
android:inputType="textMultiLine" >
can anyone add example with my code how i get value in this editext and add it to form
for post both image and value of this edittext?
instead of this
conn.setRequestProperty("firstName", "Stephen");
u have to use
conn.setRequestProperty("firstName", urDetailEdtTxt.getText().toString());
for this kind of post request u need a Key-Value pair if the key is firstName then it will work other wise replace the key with correct one.