How to store video content in SQLite database (not

2019-08-26 18:45发布

I want to store a video in sqlite database. P.S. I do not want to store the path but the actual video contents. I have converted the video in byte array and stored byte array in sqlite database. Upon retrieval bytearray is being converted into File. But video is not playing. Please help.

2条回答
Juvenile、少年°
2楼-- · 2019-08-26 19:26

You can use this approach

When save the video, save it in app private storage folder.

Context.getFilesDir()

This will give you the path to the app storage in ..\Andorid\data\data\com.example.app and it will be in internal storage.

Where com.example.app will be your application package id. You can make a new folder here like Videos then save videos in this folder. Save its path in the DB. Only your app can access to this folder. No any other app or device user can access this folder. So no one can edit or delete your files except your application.

Moreover if user reset mobile this data will be deleted as well as your database and maybe your app too in some cases. So no need to worry about it that your files will be deleted but database has still their path. If file deleted then DB deleted too as well but only when app Uninstall, device reset or SD card erase.

查看更多
神经病院院长
3楼-- · 2019-08-26 19:35

I want to store a video in sqlite database. P.S. I do not want to store the path but the actual video contents.

Unless the videos are very short and take up little space (say up to 200k each, perhaps 1/10th of a second but would depend upon the format it is saved in) then you would likely encounter issues and exceptions/crashes.

  • Using a phone around 2 seconds of black took up 2.2Mb, 2 seconds of actually recording a video took up 7Mb.

Although SQLite has the ability to store relative large BLOB's as per :-

  • Maximum length of a string or BLOB

    The maximum number of bytes in a string or BLOB in SQLite is defined by the preprocessor macro SQLITE_MAX_LENGTH. The default value of this macro is 1 billion (1 thousand million or 1,000,000,000). You can raise or lower this value at compile-time using a command-line option like this:

    -DSQLITE_MAX_LENGTH=123456789 The current implementation will only support a string or BLOB length up to 231-1 or 2147483647. And some built-in functions such as hex() might fail well before that point. In security-sensitive applications it is best not to try to increase the maximum string and blob length. In fact, you might do well to lower the maximum string and blob length to something more in the range of a few million if that is possible.

    During part of SQLite's INSERT and SELECT processing, the complete content of each row in the database is encoded as a single BLOB. So the SQLITE_MAX_LENGTH parameter also determines the maximum number of bytes in a row.

    The maximum string or BLOB length can be lowered at run-time using the sqlite3_limit(db,SQLITE_LIMIT_LENGTH,size) interface. Limits In SQLite

The Android SDK's CursorWindow has a limitation of 2Mb and that is for all the columns of the row(s) if buffers. As such even if you can store Videos successfully, you may not be able to retrieve those Videos.

The recommended way is what you don't want, that is to store the path to the Video.

If i store the video in my internal/external storage and store the path instead then how will i be able to access the same from some other device.

You would have the same issue with the database as it's typically stored within the Applications data which is protected. That is unless the database is a pre-existing database (i.e. populated with data), in which case the database is distributed with the App via the APK.

If the latter, a pre-existing database distributed via the APK, then the videos can also be distributed as part of the APK and hence as protected as and as exposable as the database.

If your intention is to distribute videos between devices that are not part of the APK then SQlite is probably not the correct solution as it's an embedded database and has no client/server functionality built in.

Besides what if my device gets formatted then I will lose all the data.

In such a scenario, the database would be as vulnerable as any other data, as that is all the database is, a file, just like a video, a word document etc which all need a suitable application to view/change the content. However, if the database is a pre-existing database, then simply re-installing the App would restore the database and other files from the APK.

Working Example

This uses the Suggested/Recommended method assuming the videos are to be distributed with the APK.

After creating new project 4 videos were downloaded and copied into the res/raw folder (after creating the raw folder) as per :-

enter image description here

The Database Helper (subclass of SQLiteOpenHelper) was created for a 2 column table an with - _id column (note named _id for use with SimpleCursorAdapter). - video_path for storing the path/name of the video (not the full path but sufficient to be able to determine the path from the data stored) - Note UNIQUE has been coded to stop duplicates being added.

With some basic method to allow rows to be added and deleted and for all rows to be extracted (via a Cursor for use with the SimpleCursorAdapter).

DBHelper.java

public class DBHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "myvideos";
    public static final int DBVERSION = 1;

    public static final String TBL_VIDEO = "video";

    public static final String COL_VIDEO_ID = BaseColumns._ID;
    public static final String COL_VIDEO_PATH = "video_path";


    SQLiteDatabase mDB;

    public DBHelper(Context context) {
        super(context, DBNAME, null, DBVERSION);
        mDB = this.getWritableDatabase();
    }


    @Override
    public void onCreate(SQLiteDatabase db) {

        String crt_video_table = "CREATE TABLE IF NOT EXISTS " + TBL_VIDEO + "(" +
                COL_VIDEO_ID + " INTEGER PRIMARY KEY," +
                COL_VIDEO_PATH + " TEXT UNIQUE" +
                ")";
        db.execSQL(crt_video_table);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public long addVideo(String path) {
        ContentValues cv = new ContentValues();
        cv.put(COL_VIDEO_PATH,path);
        return mDB.insert(TBL_VIDEO,null,cv);
    }

    public Cursor getVideos() {
        return mDB.query(TBL_VIDEO,null,null,null,null,null,null);
    }

    public int deleteVideoFromDB(long id) {
        String whereclause = COL_VIDEO_ID + "=?";
        String[] whereargs = new String[]{String.valueOf(id)};
        return mDB.delete(TBL_VIDEO,whereclause,whereargs);
    }
}

A pretty straigforward MainActivity.java (see comments)

public class MainActivity extends AppCompatActivity {

    TextView mMyTextView;
    ListView mVideoList;
    VideoView mVideoViewer;
    DBHelper mDBHlpr;
    Cursor mCsr;
    SimpleCursorAdapter mSCA;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMyTextView =  this.findViewById(R.id.mytext);
        mVideoList = this.findViewById(R.id.videolist);
        mVideoViewer = this.findViewById(R.id.videoviewer);

        mDBHlpr = new DBHelper(this);
        addVideosFromRawResourceToDB();
    }

    @Override
    protected void onDestroy() {
        mCsr.close(); //<<<<<<<<<< clear up the Cursor
        super.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        manageListView(); //<<<<<<<<<< rebuild and redisplay the List of Videos (in case they have changed) 
    }

    /**
     *  Setup or Refresh the ListView adding the OnItemClick and OnItemLongClick listeners
     */
    private void manageListView() {
        mCsr = mDBHlpr.getVideos();

        // Not setup so set it up
        if (mSCA == null) {
            // Instantiate the SimpleCursorAdapter
            mSCA = new SimpleCursorAdapter(
                    this,
                    android.R.layout.simple_list_item_1, // Use stock layout
                    mCsr, // The Cursor with the list of videos
                    new String[]{DBHelper.COL_VIDEO_PATH}, // the column (columns)
                    new int[]{android.R.id.text1}, // the view id(s) into which the column(s) data will be placed
                    0 
            );
            mVideoList.setAdapter(mSCA); // Set the adpater for the ListView
            /**
             * Add The Long Click Listener (will delete the video row from the DB (NOT the video))
             */
            mVideoList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                    mDBHlpr.deleteVideoFromDB(id);
                    manageListView(); // <<<<<<<<<< refresh the ListView as data has changed
                    return true;
                }
            });
            /**
             * Play the respective video when the item is clicked
             * Note Cursor should be at the correct position so data can be extracted directly from the Cursor
             */
            mVideoList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    setCurrentVideo(mCsr.getString(mCsr.getColumnIndex(DBHelper.COL_VIDEO_PATH)));
                }
            });
        } else {
            mSCA.swapCursor(mCsr); //<<<<<<<<<< apply the changed Cursor
        }
    }

    /**
     * Set the currrent video and play it
     * @param path the path (resource name of the video)
     */
    private void setCurrentVideo(String path) {

        mVideoViewer.setVideoURI(
                Uri.parse(
                       "android.resource://" + getPackageName() + "/" + String.valueOf(
                               getResources().getIdentifier(
                                       path,
                               "raw",
                               getPackageName())
                       )
                )
        );
        mVideoViewer.start();
    }

    /**
     *  Look at all the resources in the res/raw folder and add the to the DB (not if they are duplicates due to UNQIUE)
     */
    private void addVideosFromRawResourceToDB() {
            Field[] fields=R.raw.class.getFields();
            for(int count=0; count < fields.length; count++){
                Log.i("Raw Asset: ", fields[count].getName());
                mDBHlpr.addVideo(fields[count].getName());
            }
    }
}

Results

When first started (nothing plays) :-

enter image description here

After long clicking the 1Mb video (deleting the DB entry) :-

enter image description here

After clicking A Video in the List :-

enter image description here

查看更多
登录 后发表回答