Загрузите массив с использованием httpurlconnection multipart / form-data

11

Мне нужно загрузить Arraylistизображения на сервер без использования какой-либо библиотеки. Я использую Asynctaskдля загрузки одного изображения, и он отлично работает с помощью httpurlconnection multipart / form-data. Теперь мне нужно изменить свой код, чтобы загрузить несколько файлов любого типа с помощью, Arraylist<String>но моя проблема в том, что существующий код FileinputStreamне поддерживает arraylist, и я не представляю, что использовать вместо Fileinputstreamзагрузки arraylist на сервер, и я не хочу использовать любую библиотеку для этого либо.

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


}

Я также пытался FileInputStreamзациклить, но загрузка изображений в несколько запросов не то, что я хочу. Мой сервер требует, чтобы приложение делало один запрос на n изображений. Любая помощь будет полезна, но без использования какой-либо библиотеки

Риту
источник
Http классы устарели, использовать модернизацию или другую библиотеку
Jaiprakash Soni
Вы можете использовать модернизацию и загружать несколько изображений в одном запросе
Priyankagb

Ответы:

4

Обратите внимание, что я не пробовал, если этот код действительно работает с HttpURLConnection, но он должен.

Из того, что я прочитал из интернета, вы все еще можете использовать тот цикл, который вы упомянули, но с некоторыми изменениями.

Я следовал руководству по multipart / form-data здесь dev.to , чтобы сделать это больше учебным постом, я расскажу вам, что это за метод, что должно произойти.

Данные multipart / form отправляются следующим образом

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

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

data2
--boundary--

Я хотел бы создать новый метод, но вы можете просто написать код в уже существующем методе.

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

Вы хотите написать это граница, за которой следует расположение, а затем данные . Сделайте это для всех файлов, а затем отправьте закрывающую границу . Это сгенерирует нужную вам структуру multipart / form-data .

В псевдокоде это будет

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

Код может быть написан так, сначала вы определяете свои переменные

ByteArrayOutputStream message = null;
DataOutputStream stream = null;

FileInputStream fileInputStream;

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

Здесь данные будут генерироваться. Он начинается с конкатенации границы и последующего чтения данных. Эти данные записываются в поток, и вы продолжаете цикл для всех файлов / изображений.

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

Теперь байтовый массив sendDataбудет содержать данные multipart / form, которые вам нужно отправить с помощью HttpURLConnection.

Я не был так активен здесь в течение долгого времени. Скажите, если вам нужна дополнительная спецификация или я уточню свой текст: D

HARDCODED
источник
Если я запускаю цикл, то мне нужно сделать несколько запросов на загрузку массива. Мне нужно загрузить массив на сервер в один вызов.
Риту
Из того, что я понял, вы хотите отправить n изображений на сервер за один вызов HttpURLConnection. Вы можете попробовать использовать формат zip, где вы вводите файлы с помощью ZipEntry, иначе то, что я написал, все равно будет только одним запросом. @Ritu
HardCoded
Возможно ли для вас использовать цикл за пределами вашей асинхронной задачи? Например, если у вас есть 3 файла для загрузки, вы выполняете 3 асинхронные задачи независимо друг от друга. Таким образом, если обнаружена проблема или проблема для изображения (процесс загрузки), другие изображения (процессы) продолжают загружаться. Хотя каждая асинхронная задача заканчивается, вы можете посчитайте счетчиком в своем классе и сохраните время задержки (расчетное время), если необходимо (для оповещения о наличии проблемы при загрузке).
Маниак
1
@maniaq это не оптимальный код для запуска нескольких асинхронных задач для одной и той же задачи. Мы должны избегать сетевых вызовов везде, где можем.
androidXP
0

FileinputStream не поддерживает ArrayList. Но есть способ обойти использование ObjectOutputStream . Он также будет сериализовать ваш ArrayList. Проверьте изменения в коде.

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

Удачного кодирования :)

Аттик ур Рехман
источник
0

Не уверен, что использование одной асинхронной задачи является обязательным для вас.

Как вы сказали, ваш код работает абсолютно нормально для одного изображения. Поэтому для загрузки нескольких файлов из arraylist вам просто нужно немного изменить AsyncTask. Просто загружайте один файл за другим. Или, если вы даже не хотите вносить много изменений, просто объявите глобальную переменную, содержащую индекс загружаемого элемента, и в OnPostExecute создайте новый экземпляр асинхронной задачи и передайте следующий элемент в массив. Надеюсь, это понятно.

mayank1513
источник