使用 httpurlconnection multipart/form-data 上传数组列表
Posted
技术标签:
【中文标题】使用 httpurlconnection multipart/form-data 上传数组列表【英文标题】:Upload arraylist using httpurlconnection multipart/form-data 【发布时间】:2020-04-25 13:56:47 【问题描述】:我需要在不使用任何库的情况下将 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 & 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 类已弃用,使用改造或其他库 您可以使用改造并在单个请求中上传多个图像 【参考方案1】:请注意,如果此代码确实可以与 HttpURLConnection 一起使用,我没有尝试过,但应该可以。
根据我从互联网上读到的内容,您仍然可以使用您提到的那个循环,但需要进行一些修改。
我在dev.to 上按照multipart/form-data 上的教程进行操作,为了让这篇文章更像是一篇学习文章,我会告诉你这个方法应该发生什么。
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)
你要写的是boundary,然后是disposition,然后是data。对所有文件执行此操作,然后发送结束边界。这将生成您想要的 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];
这里是生成数据的地方。 它从连接 boundary 开始,然后读取数据。该数据被写入流中,然后您继续循环所有文件/图像。
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
将包含您需要通过HttpURLConnection 发送的multipart/form-data。
我已经很久没有在这里活跃了。告诉我您是否需要更多规范或我澄清我的文字:D
【讨论】:
如果我运行循环,那么我需要发出多个数组上传请求。我需要在一次调用中将数组上传到服务器。 据我了解,您想在单个 HttpURLConnection 调用中将 n 个图像发送到服务器。您可以尝试使用 zip 格式,在其中使用 ZipEntry 输入文件,否则我写的内容仍然只是一个请求。 @Ritu 您是否可以在 asynctask 之外使用循环? .例如,如果你有3个文件要上传,你独立执行3个异步任务。这样,如果一个图像(上传过程)发现问题或问题,其他图像(过程)继续上传。当每个异步任务结束时你可以通过您班级中的计数器计数,并在需要时保留延迟时间(估计时间)(以提醒上传中存在问题)。 @maniaq 这不是为同一任务运行多个异步任务的最佳代码。我们应该尽可能避免网络调用。【参考方案2】: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();
快乐编码:)
【讨论】:
【参考方案3】:不确定是否必须使用单个异步任务。
正如您所说,您的代码对于单张图片来说绝对可以正常工作。因此,要从 arraylist 上传多个文件,您只需稍微修改一下 AsyncTask。 只需要一个接一个地上传文件 或者,如果您不想做太多修改,只需声明全局变量来保存正在上传的项目的索引,然后在 OnPostExecute 中创建异步任务的新实例并传递数组列表中的下一项。希望这很清楚。
【讨论】:
以上是关于使用 httpurlconnection multipart/form-data 上传数组列表的主要内容,如果未能解决你的问题,请参考以下文章