我正在尝试发布ZIP存档。
我有一个网站,可以上传文件。只需使用文件选择器选择文件即可。单击“上传”按钮时,网站会重新加载。在网站重新加载之前,它会检查是否有通过POST提交的文件。因此,如果选择了文件,则会将文件复制到文件夹(包括一些重命名操作)。这是我网站上的整个上传过程,它运行正常。
我想在我的Android应用中使用此服务。我只想提交文件,以便PHP代码可以完成剩下的工作。我关注了一些SO帖子和教程,但在检查了fileZilla后,我遗憾地注意到,目录中没有文件,应该在哪里。
我正在使用AsyncTask。我有三个扩展AsyncTask的类,所以我对此很熟悉。 AsyncTask-Code似乎也运行良好。问题是我在doInBackground方法中的上传代码。
这就是我的代码的样子:
protected String doInBackground(String... sUrl)
{
HttpURLConnection conn = null;
DataOutputStream dOut = null;
DataInputStream dIn = null;
String filename = path;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
String urlString = Constants.URL_UPLOAD;
try
{
// ********************** Client Request
FileInputStream fileIn = new FileInputStream(new File(filename));
URL url = new URL(urlString);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data);boundary="+boundary);
conn.setRequestProperty("Cookie", Constants.COOKIE_KEY + "=" + Constants.cookie);
dOut = new DataOutputStream(conn.getOutputStream());
dOut.writeBytes(twoHyphens + boundary + lineEnd);
dOut.writeBytes("Content-Disposition: form-data; name=\"fileupload\";filename=\"" + path + "\"" + lineEnd);
dOut.writeBytes(lineEnd);
bytesAvailable = fileIn.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileIn.read(buffer, 0, bufferSize);
while(bytesRead > 0)
{
dOut.write(buffer, 0, bufferSize);
bytesAvailable = fileIn.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileIn.read(buffer, 0, bufferSize);
}
dOut.writeBytes(lineEnd);
dOut.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
fileIn.close();
dOut.flush();
dOut.close();
}
catch(MalformedURLException ex)
{
Log.e("Debug", "error: " + ex.getMessage(), ex);
}
catch(IOException ioex)
{
Log.e("Debug", "error: " + ioex.getMessage(), ioex);
}
try
{
dIn = new DataInputStream(conn.getInputStream());
String str;
while((str = dIn.readLine()) != null)
{
Log.e("Debug", "Server Response " + str);
responseData = str;
}
dIn.close();
}
catch(IOException ioex)
{
Log.e("Debug", "error: " + ioex.getMessage(), ioex);
}
return null;
}
我想,我的错误就在那一行:
dOut.writeBytes("Content-Disposition: form-data; name=\"fileupload\";filename=\"" + path + "\"" + lineEnd);
我认为该行定义了Http-Header。 首先,我只使用字符串作为其他帖子中使用的“名称”。一些研究告诉我,我必须使用我的表单中该字段的name-tag的值,其中包含我想要发布的值。在我的情况下,这将是文件选择器,其名称为“fileupload”。 (或者我应该采用我的表格名称,即“上传”?) 让我困惑的另一点是“文件名”的值。我应该使用整个路径,例如“path / to / android.app.zip”,还是应该使用文件名:“android.app.zip”?
另外我认为,必须有更多的错误,因为我尝试了名称和文件名的所有组合。
我希望有人发现错误。
感谢您的帮助!
答案 0 :(得分:0)
我找到了解决方案,但它确实有效。 我没有太大变化,但我认为那里有一些小错误,其他帖子中没有提到过。我将在我的代码中评论一些重要的观点。另外,我在服务器上的目录中添加了777权限。不知道它有帮助,但是,正如我所说,在给定的权限和错误修复后我的代码工作。
protected String doInBackground(String... sUrl)
{
HttpURLConnection conn = null;
DataOutputStream dOut = null;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBuffersize = 1*1024*1024;
File file = new File(path);
//path was declared in the constructor of my AsyncTask-Class.
// path has to look like this: /storage/some/dirs/myarchive.zip, when you use a .zip
//At this point it is clear, that you have to use the full path, but many posts just used
// a simple name like "file" as an example in the following code, which confused me.
try
{
FileInputStream fileIn = new FileInputStream(file);
URL url = new URL(Constants.URL_UPLOAD);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Cookie", Constants.COOKIE_KEY + "=" + Constants.cookie);
//There wasn't even one tutorial or post, which uses cookies. That was a problem, too.
//When you have a serious website, not just an example, then you possibly use cookies.
//My constant "COOKIE_KEY" describes the cookie key (or name) you defined in your php code
//and .cookie is just the value. For example it could look like this "user_cookie=MrFoo", when the cookie contains the username of a "MrFoo"
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("fileupload", path);
dOut = new DataOutputStream(conn.getOutputStream());
dOut.writeBytes(twoHyphens + boundary + lineEnd);
dOut.writeBytes("Content-Disposition: form-data; name=\"fileupload\";filename=\"" + path + "\"" + lineEnd);
//Here you have to use the field in your html/php-code, which contains the file after "name"
//In my case it was a file chooser (input type="file"), which has the name="fileupload".
//There wasn't any post again, where it was explained what kind of value is expected here.
dOut.writeBytes(lineEnd);
bytesAvailable = fileIn.available();
bufferSize = Math.min(bytesAvailable, maxBuffersize);
buffer = new byte[bufferSize];
bytesRead = fileIn.read(buffer, 0, bufferSize);
while(bytesRead > 0)
{
dOut.write(buffer, 0, bufferSize);
bytesAvailable = fileIn.available();
bufferSize = Math.min(bytesAvailable, maxBuffersize);
bytesRead = fileIn.read(buffer, 0, bufferSize);
}
dOut.writeBytes(lineEnd);
dOut.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
responseCode = conn.getResponseCode();
String responseMessage = conn.getResponseMessage();
Log.i("UPLOAD", "HTTP Response is: " + responseCode + ": " + responseMessage);
if(responseCode == 200)
{
return null;
}
fileIn.close();
dOut.flush();
dOut.close();
}
catch(MalformedURLException e)
{
return e.toString();
}
catch(Exception e)
{
return e.toString();
}
return responseCode + "";
}
如果有人想查看其他代码,例如onPostExecute,请参阅此处:
private Context context;
private ProgressDialog dialog;
private String path;
private PowerManager.WakeLock wakeLock;
private int responseCod
public UploadTask(Context ctx, ProgressDialog dialog, String path)
{
context = ctx;
this.dialog = dialog;
this.path = path;
responseCode = 0;
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
//locks CPU to prevend shut down during download
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
wakeLock.acquire();
dialog.show();
}
@Override
protected void onProgressUpdate(Integer... progress)
{
super.onProgressUpdate(progress);
dialog.setIndeterminate(false);
dialog.setMax(100);
dialog.setProgress(progress[0]);
}
protected void onPostExecute(String result)
{
wakeLock.release();
dialog.dismiss();
if(result != null)
Toast.makeText(context, "Upload error: " + result, Toast.LENGTH_LONG).show();
else
Toast.makeText(context, "File uploaded!!", Toast.LENGTH_SHORT).show();
}
只有一个进度对话框和其他内容。
我希望我可以帮助任何人。