sql >> Databasteknik >  >> RDS >> SQLite

Hur man lagrar videoinnehåll i SQLite-databasen (inte videosökvägen)

Jag vill lagra en video i SQLite-databasen. P.S. Jag vill inte lagra sökvägen utan det faktiska videoinnehållet.

Om inte videorna är väldigt korta och tar liten plats (säg upp till 200 000 vardera, kanske 1/10 av en sekund men beror på formatet de sparas i) så skulle du troligen stöta på problem och undantag/krascher.

  • Att använda en telefon med cirka 2 sekunder svart tog upp 2,2 Mb, 2 sekunder av att faktiskt spela in en video tog upp 7 Mb.

Även om SQLite har förmågan att lagra relativt stora BLOB's enligt :-

  • Maximal längd på en sträng eller BLOB

    Det maximala antalet byte i en sträng eller BLOB i SQLite definieras av förprocessormakrot SQLITE_MAX_LENGTH. Standardvärdet för detta makro är 1 miljard (1 tusen miljoner eller 1 000 000 000). Du kan höja eller sänka detta värde vid kompilering med hjälp av ett kommandoradsalternativ så här:

    -DSQLITE_MAX_LENGTH=123456789 Den aktuella implementeringen kommer bara att stödja en sträng eller BLOB-längd upp till 231-1 eller 2147483647. Och vissa inbyggda funktioner som hex() kan misslyckas långt före den tidpunkten. Osäkerhetskänsliga applikationer är det bäst att inte försöka öka den maximala strängen och bloblängden. I själva verket kan du göra klokt i att sänka den maximala strängen och klumplängden till något mer i intervallet några miljoner om det är möjligt.

    Under en del av SQLites INSERT- och SELECT-bearbetning kodas hela innehållet i varje rad i databasen som en enda BLOB. Så parametern SQLITE_MAX_LENGTH bestämmer också det maximala antalet byte i en rad.

    Den maximala strängen eller BLOB-längden kan sänkas under körning med gränssnittet thesqlite3_limit(db,SQLITE_LIMIT_LENGTH,size). Gränser i SQLite

Android SDK:s CursorWindow har en begränsning på 2 Mb och det är för alla kolumner i raden/raderna om buffertar. Som sådan, även om du kan lagra videor framgångsrikt, kanske du inte kan hämta dessa videor.

Det rekommenderade sättet är det du inte vill ha, det vill säga att lagra sökvägen till videon.

Om jag lagrar videon i mitt interna/externa minne och lagrar sökvägen istället, hur ska jag kunna komma åt densamma från någon annan enhet.

Du skulle ha samma problem med databasen eftersom det vanligtvis lagras i applikationsdata som är skyddade. Det är såvida inte databasen är en redan existerande databas (d.v.s. fylld med data), i vilket fall databasen distribueras med appen via APK.

Om det senare är en redan existerande databas som distribueras via APK-filen, kan videorna också distribueras som en del av APK-filen och därmed lika skyddade och exponerade som databasen.

Om din avsikt är att distribuera videor mellan enheter som inte är en del av APK-filen är SQlite förmodligen inte den korrekta lösningen eftersom det är en inbäddad databas och inte har någon klient/serverfunktion inbyggd.

Förutom om min enhet formateras så kommer jag att förlora all data.

I ett sådant scenario skulle databasen vara lika sårbar som alla andra data , eftersom det är allt som databasen är, en fil, precis som en video, ett word-dokument etc som alla behöver en lämplig applikation för att visa/ändra innehållet. Men om databasen är en redan existerande databas, då helt enkelt ominstallera appen skulle återställa databasen och andra filer från APK.

Arbetsexempel

Detta använder metoden Föreslagna/rekommenderade, förutsatt att videorna ska distribueras med APK:n.

  • Observera videor med tillstånd av exempelvideor

Efter att ha skapat ett nytt projekt laddades 4 videor ner och kopierades till res/raw-mappen (efter att ha skapat råmappen) enligt :-

Databashjälpen (underklass till SQLiteOpenHelper) skapades för en tabell med två kolumner och med- _id kolumn (anteckning med namnet _id för användning med SimpleCursorAdapter ).- video_path för att lagra sökvägen/namnet på videon (inte den fullständiga sökvägen men tillräckligt för att kunna bestämma sökvägen från lagrad data)- Notera UNIQUE har kodats för att stoppa dubbletter som läggs till.

Med någon grundläggande metod för att tillåta rader att läggas till och raderas och för att alla rader ska extraheras (via en markör för användning med 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);
    }
}

En ganska enkel MainActivity.java (se kommentarer)

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());
            }
    }
}

Resultat

När den startade (ingenting spelas) :-

Efter lång klickning på 1 Mb-videon (ta bort DB-posten) :-

Efter att ha klickat på en video i listan :-



  1. SQL Hur man uppdaterar SUMMA för kolumn över grupp i samma tabell

  2. Använda String[] selectionArgs i SQLiteDatabase.query()

  3. Konfigurationsparameter work_mem i PostgreSQL på Linux

  4. Viloläge:Skapa Mysql InnoDB-tabeller istället för MyISAM