java – 将大型(视频)文件从Android发送到PHP Server

我正在尝试将
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();
        }
    }
}
点赞