首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在SQLite数据库中存储视频内容(不是视频路径)

问如何在SQLite数据库中存储视频内容(不是视频路径)
EN

Stack Overflow用户
提问于 2019-02-15 18:27:58
回答 2查看 6.1K关注 0票数 0

我想在sqlite数据库中存储一个视频。附言:我不想存储路径,而是实际的视频内容。我已经将视频转换为字节数组,并将字节数组存储在sqlite数据库中。在检索时,bytearray将被转换为File。但是视频没有播放。请帮帮忙。

EN

回答 2

Stack Overflow用户

发布于 2019-02-16 10:30:39

我想在sqlite数据库中存储一个视频。附言:我不想存储路径,而是实际的视频内容。

除非视频非常短并且占用的空间很小(例如每个视频占用200k,可能是1/10秒,但这取决于它的保存格式),否则您可能会遇到问题和异常/崩溃。

  • 使用2秒左右的黑色手机占用了2.2Mb,2秒实际录制视频占用了7Mb。

尽管SQLite能够存储相对较大的BLOB,如下所示:

  • 字符串或BLOB的最大长度

SQLite中字符串或BLOB的最大字节数由预处理器宏SQLITE_MAX_LENGTH定义。此宏的默认值为10亿(10亿或1,000,000,000)。您可以在编译时使用如下命令行选项提高或降低此值:

-DSQLITE_MAX_LENGTH=123456789当前实现将仅支持最大长度为231-1或2147483647的字符串或BLOB。而一些内置函数,比如hex(),可能会在此之前很久就失败。在安全敏感的应用程序中,最好不要尝试增加最大字符串和blob长度。实际上,如果可能的话,您可以将最大字符串和blob长度降低到几百万之间。

在SQLite的INSERT和SELECT处理过程中,数据库中每一行的完整内容被编码为一个BLOB。因此,SQLITE_MAX_LENGTH参数还决定了一行中的最大字节数。

最大字符串或BLOB长度可以在运行时使用sqlite3_limit(db,SQLITE_LIMIT_LENGTH,size)接口降低。Limits In SQLite

Android SDK的CursorWindow有2Mb的限制,这是针对行(S) if缓冲区的所有列。因此,即使您可以成功存储视频,也可能无法检索这些视频。

视频的推荐方式是你不想要的,那就是存储的路径。

如果我将视频存储在内部/外部存储中,而不是存储路径,那么我如何能够从其他设备访问相同的视频。

对于数据库,您将遇到相同的问题,因为它通常存储在受保护的应用程序数据中。除非数据库是预先存在的数据库(即,填充了数据),在这种情况下,数据库通过APK与应用程序一起分发。

如果后者是通过APK分发的预先存在的数据库,则视频也可以作为APK的一部分分发,因此与数据库一样受保护且同样可公开。

如果您的意图是在不属于APK的设备之间分发视频,那么SQlite可能不是正确的解决方案,因为它是嵌入式数据库,没有内置的客户端/服务器功能。

除此之外,如果我的设备被格式化了,我会丢失所有的数据。

在这种情况下,数据库将像任何其他数据一样易受攻击,因为这就是数据库的全部,一个文件,就像一个视频,一个word文档等,所有这些都需要一个合适的应用程序来查看/更改内容。但是,如果数据库是预先存在的数据库,则只需重新安装应用程序即可从APK恢复数据库和其他文件。

工作示例

这将使用建议/推荐的方法,假设视频将随APK一起分发。

提供的

  • 笔记视频

创建新项目后,下载了4个视频,并将其复制到res/raw文件夹(创建原始文件夹后),如下所示:-

​

​

数据库帮助器(SQLiteOpenHelper的子类)是为一个包含两列的表创建的,其中包含- _id列(注意,命名为_id以便与SimpleCursorAdapter一起使用)。-用于存储视频的路径/名称的video_path (不是完整路径,但足以从存储的数据中确定路径)-注唯一已编码为停止添加重复项。

使用一些基本方法来允许添加和删除行,以及提取所有行(通过与SimpleCursorAdapter一起使用的游标)。

DBHelper.java

代码语言:javascript
复制
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);
    }
}

一个非常简单的MainActivity.java (参见评论)

代码语言:javascript
复制
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());
            }
    }
}

结果

第一次启动时(无播放) :-

​

​

长时间点击1Mb视频(删除DB条目)后:-

​

​

单击列表中的视频后:-

​

​

票数 6
EN

Stack Overflow用户

发布于 2019-02-15 19:43:49

您可以使用此方法

保存视频时,将其保存在app私有存储文件夹中。

代码语言:javascript
复制
Context.getFilesDir()

这将为您提供..\Andorid\data\data\com.example.app中应用程序存储的路径,它将位于内部存储中。

其中com.example.app将是您的应用程序包id。您可以在此处创建一个新文件夹,如Videos,然后将视频保存在此文件夹中。将其路径保存在数据库中。只有你的应用才能访问此文件夹。任何其他应用程序或设备用户都无法访问此文件夹。因此,除了您的应用程序之外,没有人可以编辑或删除您的文件。

此外,如果用户重置移动设备,在某些情况下,这些数据将被删除,您的数据库可能还会删除您的应用程序。所以不需要担心你的文件会被删除,但是数据库仍然有它们的路径。如果文件被删除,那么DB也会被删除,但仅当应用程序Uninstall, device reset或SD card erase时才会删除。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54707299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档