Cargue la lista de matrices usando httpurlconnection multipart / form-data

11

Necesito subir Arraylistimágenes al servidor sin usar ninguna biblioteca. Estoy usando Asynctaskpara cargar una sola imagen y funciona perfectamente con la ayuda de httpurlconnection multipart / form-data. Ahora necesito cambiar mi código para cargar múltiples archivos de cualquier tipo usando, Arraylist<String>pero mi problema es que el código existente FileinputStreamno admite la lista de arrays y no tengo idea de qué usar en lugar de Fileinputstreamcargar la lista de arrays en el servidor y no quiero usar cualquier biblioteca para esto tampoco.

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


    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;
    }


}

También intenté ponerlo FileInputStreamen bucle, pero cargar imágenes en solicitudes múltiples no es lo que quiero. La aplicación de mi servidor requiere que realice una solicitud única para n número de imágenes. Cualquier ayuda sería apreciada pero sin el uso de ninguna biblioteca.

Ritu
fuente
Las clases de http están en desuso, use retrofit u otra biblioteca
Jaiprakash Soni
puede usar la actualización y cargar varias imágenes en una sola solicitud
Priyankagb

Respuestas:

4

Tenga en cuenta que no lo he intentado si este código realmente funciona con HttpURLConnection, pero debería.

Por lo que he leído en Internet, aún puedes usar el ciclo que mencionaste pero con algunas modificaciones.

Seguí el tutorial sobre multipart / form-data aquí dev.to , para que esto sea más una publicación de aprendizaje, te diré qué es este método y qué debería suceder.

Los datos multiparte / formulario se envían así

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

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

data2
--boundary--

Lo que haría es crear un nuevo método, pero puede escribir el código en su método ya existente.

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

Desea escribir es el límite seguido de la disposición y luego los datos . Haga eso para todos los archivos y luego envíe el límite de cierre . Esto generará los datos multiparte / formulario estructura que desee.

En psudocódigo esto sería

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

El código podría escribirse así, primero debes definir tus variables

ByteArrayOutputStream message = null;
DataOutputStream stream = null;

FileInputStream fileInputStream;

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

Aquí es donde se generarán los datos. Comienza con la concatenación del límite y luego la lectura de los datos. Esos datos se escriben en la secuencia y continúa el ciclo para todos los archivos / imágenes.

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();
}

Ahora, la matriz de bytes sendDatacontendrá los datos multiparte / formulario que debe enviar con su HttpURLConnection.

No he estado tan activo aquí por mucho tiempo. Dime si necesitas más especificaciones o si aclaro mi texto: D

HardCoded
fuente
Si ejecuto el bucle, entonces necesito hacer una solicitud múltiple para cargar la matriz. Necesito subir una matriz al servidor en una sola llamada.
Ritu
Por lo que entiendo es que desea enviar n imágenes al servidor en una sola llamada HttpURLConnection. Puede intentar usar un formato zip donde ingrese los archivos con ZipEntry; de lo contrario, lo que escribí seguirá siendo solo una solicitud. @Ritu
HardCoded
¿Es posible para usted que use un bucle fuera de su asinctask? Por ejemplo, si tiene 3 archivos para cargar, ejecuta 3 asintos de forma independiente. De esta manera, si se encuentra un problema o problema para una imagen (proceso de carga), otras imágenes (procesos) continúan cargándose. cuente por un contador en su clase y mantenga un tiempo de retraso (tiempo estimado) si es necesario (para alertar sobre la existencia de un problema en la carga).
maniaq
1
@maniaq no es un código óptimo para ejecutar múltiples asinctask para la misma tarea. Debemos evitar las llamadas de red siempre que podamos.
androidXP
0

FileinputStream no es compatible con ArrayList. Pero hay una forma de evitarlo usando ObjectOutputStream . También serializará su ArrayList. Verifique los cambios en el código.

       //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 :)

Attiq ur Rehman
fuente
0

No estoy seguro si usar una sola tarea asíncrona es imprescindible para usted

Como dijiste, tu código funciona absolutamente bien para una sola imagen. Entonces, para cargar varios archivos desde la lista de arrays, simplemente necesita modificar un poco su AsyncTask. Simplemente cargue un archivo después de otro O si incluso no desea hacer tanta modificación, simplemente declare la variable global que contiene el índice del elemento que se está cargando y en OnPostExecute cree una nueva instancia de la tarea asíncrona y pase el siguiente elemento en la lista de arrays. Espero que esto esté claro.

mayank1513
fuente