Wgraj arraylist używając httpurlconnection multipart / form-data


11

Muszę przesłać Arraylistobrazy na serwer bez korzystania z biblioteki. Używam Asynctaskdo przesyłania pojedynczego obrazu i działa idealnie przy pomocy httpurlconnection multipart / form-data. Teraz muszę zmienić kod, aby przesyłać wiele plików dowolnego typu za pomocą, Arraylist<String>ale moim problemem jest to, że istniejący kod FileinputStreamnie obsługuje listy arraylist i nie mam pojęcia, czego użyć zamiast Fileinputstreamprzesyłać listę arraylist na serwer, a ja nie chcę użyć do tego dowolnej biblioteki.

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


}

Próbowałem także FileInputStreamzapętlić, ale przesyłanie obrazów do wielu żądań nie jest tym, czego chcę. Aplikacja mojego serwera wymaga pojedynczego żądania n liczby obrazów. Każda pomoc byłaby mile widziana, ale bez użycia biblioteki


Klasy HTTP są przestarzałe, używaj modernizacji lub innej biblioteki
Jaiprakash Soni

możesz użyć modernizacji i przesłać wiele zdjęć w jednym żądaniu
Priyankagb

Odpowiedzi:


4

UWAGA: nie próbowałem, czy ten kod faktycznie działa z HttpURLConnection, ale powinien.

Z tego, co przeczytałem w Internecie, nadal możesz używać wspomnianej pętli, ale z pewnymi modyfikacjami.

Wykonałem samouczek dotyczący danych wieloczęściowych / formularzy tutaj dev.to , aby uczynić to bardziej postem edukacyjnym, powiem ci, co to za metoda, co powinno się stać.

Dane wieloczęściowe / formularze są wysyłane w ten sposób

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

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

data2
--boundary--

Chciałbym stworzyć nową metodę, ale możesz po prostu napisać kod w swojej już istniejącej metodzie.

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

Chcesz napisać to granica, po której następuje dyspozycja, a następnie dane . Zrób to dla wszystkich plików, a następnie wyślij granicę zamknięcia . Spowoduje to wygenerowanie pożądanej struktury danych wieloczęściowych / formularzy .

W psudo-code byłoby to

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

Kod można zapisać w ten sposób, najpierw zdefiniujesz zmienne

ByteArrayOutputStream message = null;
DataOutputStream stream = null;

FileInputStream fileInputStream;

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

Oto, gdzie zostaną wygenerowane dane. Zaczyna się od konkatenacji granicy, a następnie odczytania danych. Te dane są zapisywane w strumieniu i kontynuujesz pętlę dla wszystkich plików / obrazów.

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

Teraz tablica bajtów sendDatabędzie zawierać dane wieloczęściowe / formularze , które należy wysłać za pomocą HttpURLConnection.

Dawno nie byłem tu tak aktywny. Powiedz mi, czy potrzebujesz więcej specyfikacji lub wyjaśnię swój tekst: D


Jeśli uruchomię pętlę, muszę wysłać wiele żądań przesłania tablicy. Muszę przesłać tablicę na serwer w jednym wywołaniu.
Ritu

Z tego, co rozumiem, jest to, że chcesz wysłać n obrazów do serwera w jednym wywołaniu HttpURLConnection. Możesz spróbować użyć formatu zip, w którym wprowadzasz pliki za pomocą ZipEntry, w przeciwnym razie to, co napisałem, będzie nadal tylko jednym żądaniem. @Ritu
HardCoded

Czy to możliwe, że korzystasz z pętli poza asynchroniką? Na przykład, jeśli masz 3 pliki do przesłania, wykonujesz 3 asynctask niezależnie. W ten sposób, jeśli zostanie znaleziony problem lub problem z obrazem (proces przesyłania), inne obrazy (procesy) będą nadal przesyłane. Gdy każda asynctask kończy się, możesz policz licznik w swojej klasie i zachowaj opóźnienie (szacowany czas) w razie potrzeby (w celu zaalarmowania o istnieniu problemu z przesyłaniem).
maniaq

1
@maniaq nie jest optymalnym kodem do uruchamiania wielu asynctask dla tego samego zadania. Powinniśmy unikać połączeń sieciowych w miarę możliwości.
androidXP

0

FileinputStream nie obsługuje ArrayList. Ale można to obejść za pomocą ObjectOutputStream . Będzie również serializować twoją ArrayList. Sprawdź zmiany w kodzie.

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


0

Nie jestem pewien, czy korzystanie z pojedynczego zadania asynchronicznego jest dla Ciebie koniecznością.

Jak powiedziałeś, twój kod działa absolutnie dobrze dla pojedynczego obrazu. Aby przesłać wiele plików z listy arraylist, wystarczy trochę zmodyfikować AsyncTask. Po prostu prześlij jeden plik po drugim Lub jeśli nawet nie chcesz dokonywać tak wielu modyfikacji, po prostu zadeklaruj zmienną globalną zawierającą indeks przesyłanego elementu, a OnPostExecute utwórz nową instancję zadania asynchronicznego i przekaż następny element na liście arraylist. Mam nadzieję, że to jasne.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.