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

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

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 в l oop, но загрузка изображений в несколько запросов это не то, что я хотеть. Мой сервер требует, чтобы приложение делало один запрос на n изображений. Любая помощь будет полезна, но без использования библиотеки

Ответы [ 3 ]

4 голосов
/ 10 января 2020

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

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

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

multipart / form-data отправляется так

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

Вы хотите написать border , за которым следует disposition , а затем данные . Сделайте это для всех файлов и затем отправьте закрывающую границу 1026 *. Это сгенерирует желаемую структуру 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];

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

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-data что вам нужно отправить с вашим HttpURLConnection.

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

0 голосов
/ 17 января 2020

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

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

0 голосов
/ 17 января 2020

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

Happy Coding:)

...