Carregar lista de matrizes usando httpurlconnection multipart / form-data

11

Preciso fazer upload Arraylistde imagens para o servidor sem usar nenhuma biblioteca. Estou usando o Asynctaskupload de uma única imagem e ela está funcionando perfeitamente com a ajuda do httpurlconnection multipart / form-data. Agora eu preciso alterar meu código para fazer upload de vários arquivos de qualquer tipo usando, Arraylist<String>mas meu problema é que o código existente FileinputStreamnão suporta arraylist e não tenho idéia do que usar em vez de Fileinputstreamfazer upload de arraylist para o servidor e não quer usar qualquer biblioteca para isso também.

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


}

Eu também tentei colocar FileInputStreamem loop, mas o upload de imagens em vários pedidos não é o que eu quero. Meu servidor exige que o aplicativo faça uma solicitação única para n número de imagens. Qualquer ajuda seria apreciada, mas sem o uso de qualquer biblioteca

Ritu
fonte
Classes HTTP estão obsoletas, usam retrofit ou outra biblioteca
Jaiprakash Soni 16/01
você pode usar a atualização e fazer upload de várias imagens em uma única solicitação
Priyankagb

Respostas:

4

OBSERVAÇÃO: não tentei se esse código funciona corretamente com a HttpURLConnection, mas deveria.

Pelo que li da internet, você ainda pode usar o loop mencionado, mas com algumas modificações.

Segui o tutorial sobre multipart / form-data aqui dev.to , para tornar isso mais um post de aprendizado, vou lhe dizer qual é esse método que deve acontecer.

Os dados multipart / form são enviados assim

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

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

data2
--boundary--

O que eu faria é criar um novo método, mas você pode simplesmente escrever o código no seu método já existente.

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

Você deseja escrever é o limite seguido pela disposição e depois pelos dados . Faça isso para todos os arquivos e envie o limite de fechamento . Isso irá gerar a estrutura multipart / dados de formulário que você deseja.

No código psudo isso seria

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

O código pode ser escrito assim, primeiro você define suas variáveis

ByteArrayOutputStream message = null;
DataOutputStream stream = null;

FileInputStream fileInputStream;

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

Aqui é onde os dados serão gerados. Começa com a concatenação do limite e a leitura dos dados. Esses dados são gravados no fluxo e você continua o loop para todos os arquivos / imagens.

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

Agora, a matriz de bytes sendDataconterá os dados de várias partes / formulário que você precisa enviar com sua HttpURLConnection.

Eu não sou tão ativo aqui há muito tempo. Diga-me se você precisa de mais algumas especificações ou que esclareço meu texto: D

Codificado
fonte
Se eu executar o loop, preciso fazer várias solicitações para o upload da matriz. Preciso fazer upload de uma matriz para o servidor em uma única chamada.
Ritu 11/01
Pelo que entendi, você deseja enviar n imagens para o servidor em uma única chamada HttpURLConnection. Você pode tentar usar um formato zip no qual insira os arquivos com o ZipEntry, caso contrário, o que eu escrevi ainda será apenas uma solicitação. @Ritu
HardCoded 11/01
É possível que você use um loop fora do seu asynctask? Por exemplo, se você possui 3 arquivos para upload, executa 3 asynctask de forma independente. Dessa forma, se um problema ou problema for encontrado para uma imagem (processo de upload), outras imagens (processos) continuarão sendo carregadas. conte por um contador em sua classe e mantenha um tempo de atraso (tempo estimado), se necessário (para alertar sobre a existência de um problema no upload).
maniaq 16/01
11
@maniaq não é um código ideal para executar várias assíncronas para a mesma tarefa. Devemos evitar chamadas de rede sempre que possível.
androidXP 17/01
0

FileinputStream não suporta o ArrayList. Mas há uma maneira de contornar usando ObjectOutputStream . Também serializará seu ArrayList. Verifique as alterações no 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
fonte
0

Não tenho certeza se o uso de tarefa assíncrona única é uma obrigação para você.

Como você disse, seu código funciona absolutamente bem para uma única imagem. Portanto, para carregar vários arquivos da arraylist, basta modificar um pouco o seu AsyncTask. Basta fazer upload de um arquivo após o outro. Ou se você não quiser fazer tanta modificação, simplesmente declare a variável global que mantém o índice do item que está sendo carregado e, no OnPostExecute, crie uma nova instância da tarefa assíncrona e passe o próximo item no arraylist. Espero que isso esteja claro.

mayank1513
fonte