Home » Android » java – Upload arraylist using httpurlconnection multipart/form-data

java – Upload arraylist using httpurlconnection multipart/form-data

Posted by: admin May 14, 2020 Leave a comment

Questions:

I need to upload Arraylist of images to the server without using any library. I am using Asynctask to upload single image and it’s working perfectly with the help of httpurlconnection multipart/form-data. Now i need to change my code to upload multiple files of any type by using Arraylist<String> but my problem is the existing code’s FileinputStream don’t support arraylist and i don’t have idea what to use instead of Fileinputstream to upload arraylist to server and i don’t want to use any library for this either.

public class multipart_test extends AsyncTask<Void,Void,String> {
    Context context;
    String Images;
    public static final String TAG = "

Answer:

Image Uploading

Answer:

"; public multipart_test(Context context,String Upload_Images) { this.context = context; this.Images = Upload_Images; } @Override protected String doInBackground(Void... params) { BufferedReader reader; String WebPath = null; try { String lineEnd = "\r\n"; String twoHyphens = "--"; String boundary = "*****"; int bytesRead, bytesAvailable, bufferSize; byte[] buffer; int maxBufferSize = 1024 * 1024; //todo change URL as per client ( MOST IMPORTANT ) URL url = new URL("10.0.0.1/uploadMultipart.php"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // Allow Inputs &amp; Outputs. connection.setDoInput(true); connection.setDoOutput(true); connection.setUseCaches(false); // Set HTTP method to POST. connection.setRequestMethod("POST"); connection.setRequestProperty("Connection", "Keep-Alive"); connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); FileInputStream fileInputStream; DataOutputStream outputStream; outputStream = new DataOutputStream(connection.getOutputStream()); outputStream.writeBytes(twoHyphens + boundary + lineEnd); outputStream.writeBytes("Content-Disposition: form-data; name=\"reference\""+ lineEnd); outputStream.writeBytes(lineEnd); //outputStream.writeBytes("my_refrence_text"); outputStream.writeBytes(lineEnd); outputStream.writeBytes(twoHyphens + boundary + lineEnd); outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadFile\";filename=\"" + "profileImage" +"\"" + lineEnd); outputStream.writeBytes(lineEnd); //Dummy ArrayList for upload ArrayList<String> uploadFiles = new ArrayList<>(); uploadFiles.add(Images); uploadFiles.add(Images); uploadFiles.add(Images); uploadFiles.add(Images); fileInputStream = new FileInputStream(uploadFiles); // NOT SUPPORTING ARRAYLIST HERE bytesAvailable = fileInputStream.available(); bufferSize = Math.min(bytesAvailable, maxBufferSize); buffer = new byte[bufferSize]; // Read file bytesRead = fileInputStream.read(buffer, 0, bufferSize); while (bytesRead > 0) { outputStream.write(buffer, 0, bufferSize); bytesAvailable = fileInputStream.available(); bufferSize = Math.min(bytesAvailable, maxBufferSize); bytesRead = fileInputStream.read(buffer, 0, bufferSize); outputStream.writeBytes(lineEnd); outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); fileInputStream.close(); } // Responses from the server (code and message) int serverResponseCode = connection.getResponseCode(); String result = null; if (serverResponseCode == 200) { StringBuilder s_buffer = new StringBuilder(); InputStream is = new BufferedInputStream(connection.getInputStream()); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String inputLine; while ((inputLine = br.readLine()) != null) { s_buffer.append(inputLine); } result = s_buffer.toString(); } connection.getInputStream().close(); outputStream.flush(); outputStream.close(); if (result != null) { Log.d("result_for upload", result); } return WebPath; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ProtocolException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } }

I also tried to put FileInputStream into loop but uploading images into multiple request is not what i want. My server require’s app to make single request for n number of images. Any help would be appreciate but without use of any library

How to&Answers:

NOTE that I have not tried if this code acctually works with the HttpURLConnection but it should.

From what I’ve read from the internet you can still use that loop you mentioned but with some modifications.

I followed the tutorial on multipart/form-data here dev.to, to make this more of a learning post I’ll tell you what this method is what should happen.

The multipart/form-data is sent like this

--boundary
Content-Disposition: form-data; name="something1"

data1
--boundary
Content-Disposition: form-data; name="something2"

data2
--boundary--

What I would do is to create a new method but you can just write the code in your already existing method.

public byte[] get_multipart_data(List<String> files, String boundary)

You want to write is the boundary followed by the disposition and then the data. Do that for all the files and then you send the closing boundary. This will generate the multipart/form-data structure that you want.

In psudo-code this would be

loop for all files
    write "--boundary"
    write "Content-Disposition: ...."
    write image_data
end
write "--boundary--"

The code could be written like this, first you define your variables

ByteArrayOutputStream message = null;
DataOutputStream stream = null;

FileInputStream fileInputStream;

int maxBufferSize = 1024 * 1024;
byte[] buffer = new byte[maxBufferSize];
byte[] sendData = new byte[0];

Here is where the data will get generated.
It starts with concatenating the boundary and then reading the data. That data is written to the stream and you continue the loop for all files/images.

try {
    message = new ByteArrayOutputStream();
    stream = new DataOutputStream(message);

    // Loop though all file names
    for(String fileName : files) {
        stream.writeBytes("--" + boundary + "\r\n"); // Start boundary
        stream.writeBytes("Content-Disposition: form-data; name=\"" + fileName + "\"\r\n\r\n");

        // Read the image data
        fileInputStream = new FileInputStream(fileName);
        int readBytes = 0;
        while((readBytes = fileInputStream.read(buffer)) != -1) {
            // Write file data to output
            stream.write(buffer, 0, readBytes);
        }
        fileInputStream.close();

        stream.writeBytes("\r\n");
    }
    stream.writeBytes("--" + boundary + "--\r\n"); // Closing boundary

    sendData = message.toByteArray();
} catch(IOException e) {
    e.printStackTrace();
}

Now the byte array sendData will contain the multipart/form-data that you need to send with your HttpURLConnection.

I’ve not been that active here for a long time. Tell me if you need some more specification or that I clarify my text 😀

Answer:

FileinputStream don’t support the ArrayList. But there is a way around by using ObjectOutputStream. It will also serialize your ArrayList. Check the changes in the code.

       //Changes required in your code
        ArrayList<String> uploadFiles = new ArrayList<>();
        uploadFiles.add(Images);
        uploadFiles.add(Images);
        uploadFiles.add(Images);
        uploadFiles.add(Images);

        fileInputStream = new FileInputStream("listImages"); 
        java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fileInputStream); 
        oos.writeObject(uploadFiles);

        bytesAvailable = fileInputStream.available();
        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        buffer = new byte[bufferSize];
        ...
        ...
        ...
        oos.close();

Happy Coding 🙂

Answer:

Not sure if using single async task is a must for you.

As you said, your code works absolutely fine for single image. So for uploading multiple files from arraylist you simply need to modify your AsyncTask a bit. Just upload one file after another Or if you even don’t want to do that much modification simply declare global variable holding the index of item being uploaded and in OnPostExecute create new instance of the async task and pass the next item in the arraylist. Hope this is clear.