我正在尝试将
Android设备中的视频文件发送到服务器(使用PHP处理请求).我已经将volley用于我对同一台服务器发出的其他请求,但是当我尝试将一个视频文件(作为Base64字符串)发送到服务器时,我得到一个OutOfMemoryError.我想知道是否有办法以不同的方式发送文件(可能使用流).
这是我目前发送视频文件的方法:
private void syncFullVideos() {
checkPermissions();
if (pDialog == null || !pDialog.isShowing()) {
pDialog = new ProgressDialog(this);
pDialog.setCanceledOnTouchOutside(false);
pDialog.setMessage(getString(R.string.pDialogSync));
pDialog.show();
}
syncSucces = new boolean[syncVideos.size()];
Arrays.fill(syncSucces, Boolean.FALSE);
for (final Video video: syncVideos) {
String picturepath = video.getImage_path();
if (fileExists(picturepath)) {
File videoFile = new File(picturepath);
FileInputStream fin = null;
byte[] byte_arr = null;
try {
fin = new FileInputStream(videoFile);
byte_arr = new byte[(int)videoFile.length()];
fin.read(byte_arr);
} catch (IOException e) {
e.printStackTrace();
}
final String image_str = Base64.encodeToString(byte_arr, 0);
Log.d("SyncFullVideos", video.toString());
String tag_string_req = "string_req";
final String TAG = AppController.class
.getSimpleName();
String url = "http://android.diggin.io/diggin/v1/videos";
StringRequest strReq = new StringRequest(Request.Method.PUT,
url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d(TAG, response);
try {
final JSONObject jsonObject = new JSONObject(response);
if (!jsonObject.getBoolean("error4")) {
int index = jsonObject.getInt("index");
syncSucces[index] = true;
Log.e("AddSucces(" + (addCount + 1) + "/" + (syncVideos.size()) + ")", video.toString());
addCount++;
if (addCount == syncVideos.size()) {
refreshPhotos();
}
} else {
Log.e("AddFail(" + (addCount + 1) + "/" + (syncVideos.size()) + ")", video.toString());
addCount++;
if (addCount == syncVideos.size()) {
refreshPhotos();
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
//Send message when something goes wrong
runOnUiThread(new Runnable() {
@Override
public void run() {
pDialog.hide();
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(PictureActivity.this);
dlgAlert.setMessage(R.string.errFullSyncVids);
dlgAlert.setPositiveButton(R.string.errBtnOK, null);
dlgAlert.setCancelable(true);
dlgAlert.create().show();
}
});
}
}) {
@Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("id", String.valueOf(video.getId()));
params.put("im_path", video.getDBImage_path());
params.put("image", image_str);
params.put("index", String.valueOf(syncVideos.indexOf(video)));
return params;
}
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}
}
}
这是我用来处理请求并发送响应的PHP(我正在使用REST API):
$app->put('/videos', function() use ($app) {
// check for required params
verifyRequiredParams(array('id','im_path','image','index'));
$response = array();
$id = $app->request->put('id');
$im_path = $app->request->put('im_path');
$image = $app->request->put('image');
$index = $app->request->put('index');
$db = new DbHandler();
// update photo
$result = $db->updateVideo($id, $im_path);
if ($result) {
$response["error"] = false;
$response["message"] = "Video updated successfully";
// Decode Image
$binary=base64_decode($image);
header('Content-Type: video/mp4');
$im_path2 = explode("_",$im_path);
$im_path2[0] .= 's';
$im_path2[2] = $im_path;
$im_path3 = implode("/",$im_path2);
$filepath = '../images/'.$im_path3;
$dirname = dirname($filepath);
if (!is_dir($dirname))
{
if(mkdir($dirname, 0777, true)) {
$response["error2"] = false;
$response["message2"] = "Directory Created Succesfully";
} else {
$response["error2"] = true;
$response["error3"] = true;
$response["error4"] = true;
$response["message2"] = "Failed to create directory. Please try again";
$response["filepath"] = $filepath;
}
}
// Images will be saved under images folder
$file = fopen($filepath, 'wb');
if ($file == false) {
$response["error3"] = true;
$response["error4"] = true;
$response["message3"] = "Failed to open file. Please try again";
$response["filepath"] = $filepath;
echoRespnse(200, $response);
} else {
// Create File
$response["error3"] = false;
$response["message3"] = "File is open and good to write";
fwrite($file, $binary);
fclose($file);
if (file_exists($filepath)) {
$response["error4"] = false;
$response["message4"] = "File exists";
$response["index"] = $index;
echoRespnse(201, $response);
} else {
$response["error4"] = true;
$response["message4"] = "File doesn't exist";
echoRespnse(200, $response);
}
}
} else {
$response["error"] = true;
$response["error2"] = true;
$response["error3"] = true;
$response["error4"] = true;
$response["message"] = "Failed to update video. Please try again";
$response["id"] = $id;
$response["im_path"] = $im_path;
echoRespnse(200, $response);
}
});
最佳答案 在测试了很多不同的东西之后我发现了一种使用HttpUrlConnection的方法,这里是syncFullVideos方法的新版本:
private void syncFullVideos() {
new StreamFileTask().execute();
}
private class StreamFileTask extends AsyncTask<Void,Integer,Void> {
protected Void doInBackground(Void... params) {
syncSucces2 = new boolean[syncVideos.size()];
Arrays.fill(syncSucces2, Boolean.FALSE);
for (int i = 0; i < syncVideos.size(); i++) {
Video video = syncVideos.get(i);
String picturepath = video.getImage_path();
if (fileExists(picturepath)) {
File sourceFile = new File(picturepath);
String fileName = video.getDBImage_path();
int id = video.getId();
int index = syncVideos.indexOf(video);
HttpURLConnection conn;
DataOutputStream dos;
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1024 * 1024;
int serverResponseCode;
Log.e("VideoUpload", "Uploading: sourcefileURI, " + fileName);
if (!sourceFile.isFile()) {
Log.e("uploadFile", "Source File not exist");
} else {
try {
FileInputStream fin = new FileInputStream(sourceFile);
URL url = new URL("http://android.diggin.io/diggin/v1/vidUpload.php");
Log.v("VideoUpload", url.toString());
// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true); // Allow Inputs
conn.setDoOutput(true); // Allow Outputs
conn.setUseCaches(false); // Don't use a Cached Copy
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
conn.setRequestProperty("Content-Type", "multipart/form-data");
conn.setRequestProperty("X_FILE_NAME", fileName);
conn.setRequestProperty("VID_ID", String.valueOf(id));
conn.setRequestProperty("VID_INDEX", String.valueOf(index));
conn.setRequestProperty("CONTENT_LENGTH", String.valueOf(sourceFile.length()));
publishProgress(2, i);
dos = new DataOutputStream(conn.getOutputStream());
bytesAvailable = fin.available();
int thirdOfBytes = bytesAvailable / 3;
int state = 0;
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fin.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fin.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fin.read(buffer, 0, bufferSize);
Log.i("VideoUpload", "->");
if (bytesAvailable < thirdOfBytes && state == 1) {
publishProgress(4, i);
state = 2;
} else if (bytesAvailable < (2 * thirdOfBytes) && state == 0) {
publishProgress(3, i);
state = 1;
}
}
publishProgress(5, i);
serverResponseCode = conn.getResponseCode();
String serverResponseMessage = conn.getResponseMessage();
Log.i("VideoUpload", "HTTP Response is : " + serverResponseMessage + ": " + serverResponseCode);
publishProgress(9, i);
DataInputStream inStream;
HashMap<String,String> responseMap = new HashMap<>();
try {
inStream = new DataInputStream(conn.getInputStream());
String str;
while ((str = inStream.readLine()) != null) {
Log.e("VideoUpload", "SOF Server Response: " + str);
String[] responseItem = str.split(" - ");
responseMap.put(responseItem[0], responseItem[1]);
}
inStream.close();
if (responseMap.get("ERROR").equals("FALSE")) {
int index2 = Integer.parseInt(responseMap.get("INDEX"));
syncSucces2[index2] = true;
Log.e("AddSucces(" + (addCount + 1) + "/" + (syncVideos.size()) + ")", video.toString());
}
} catch (IOException e) {
Log.e("VideoUpload", "SOF error: " + e.getMessage(), e);
}
fin.close();
dos.flush();
dos.close();
publishProgress(10, i);
} catch (MalformedURLException ex) {
ex.printStackTrace();
Log.e("VideoUpload", "UL error: " + ex.getMessage(), ex);
} catch (Exception e) {
e.printStackTrace();
Log.e("UploadFileException", "Exception : " + e.getMessage(), e);
}
}
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0] + (values[1] * 10));
}
@Override
protected void onPreExecute() {
super.onPreExecute();
progressBar = new ProgressDialog(PictureActivity.this);
progressBar.setMax(10 * syncVideos.size());
progressBar.setMessage("Uploading Video File(s)");
progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressBar.setCancelable(false);
progressBar.show();
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
progressBar.hide();
refreshPhotos();
}
}
我也改变了PHP,而不是在index.php文件中使用部分代码(使用REST API),我创建了另一个名为uploadVideo.php的文件:
<?php
require_once '../include/File_Streamer.php';
require_once '../include/DbHandler.php';
if (!isset($_SERVER['HTTP_X_FILE_NAME']) || !isset($_SERVER['HTTP_VID_ID']) || !isset($_SERVER['HTTP_VID_INDEX'])) {
throw new Exception("Invalid Headers!");
} else {
$im_path = $_SERVER['HTTP_X_FILE_NAME'];
$id = $_SERVER['HTTP_VID_ID'];
$index = $_SERVER['HTTP_VID_INDEX'];
$db = new DbHandler();
$response = array();
if($db->updateVideo($id, $im_path)) {
$im_path2 = explode("_",$im_path);
$im_path2[0] .= 's';
$im_path2[2] = $im_path;
$im_path3 = implode("/",$im_path2);
$filepath = '../images/'.$im_path3;
$dirpath = str_replace($im_path,"",$filepath);
$ft = new File_Streamer();
$ft->setDestination(__DIR__ . '/' . $dirpath);
if ($ft->receive()) {
echo "ERROR - FALSE\n";
echo "MESSAGE - UPLOADED VIDEO WITH SUCCES\n";
echo "INDEX - " . $index;
} else {
echo "ERROR - TRUE\n";
echo "MESSAGE - FAILED TO SAVE VIDEO FILE";
}
} else {
echo "ERROR - TRUE\n";
echo "MESSAGE - FAILED TO ADD TO DATABASE";
}
}
我也在使用以下课程:
<?php
class File_Streamer
{
private $_fileName;
private $_contentLength;
private $_destination;
public function __construct()
{
if (!isset($_SERVER['HTTP_X_FILE_NAME'])
|| !isset($_SERVER['CONTENT_LENGTH'])) {
throw new Exception("Invalid Headers!");
}
$this->_fileName = $_SERVER['HTTP_X_FILE_NAME'];
$this->_contentLength = $_SERVER['CONTENT_LENGTH'];
}
public function isValid()
{
if (($this->_contentLength > 0)) {
return true;
}
return false;
}
public function setDestination($destination)
{
$this->_destination = $destination;
}
public function receive()
{
try {
if (!$this->isValid()) {
throw new Exception('No file uploaded!');
}
$fileReader = fopen('php://input', "r");
$fileWriter = fopen($this->_destination . $this->_fileName, "w+");
while(true) {
$buffer = fgets($fileReader, 4096);
if (strlen($buffer) == 0) {
fclose($fileReader);
fclose($fileWriter);
return true;
}
fwrite($fileWriter, $buffer);
}
return false;
}
catch(Exception $ex) {
echo "error: " . $ex->getMessage();
}
}
}