I want to save image using my developed app into mobile what is the best way to it.
I was trying to save via sqlite but is there any other options?
The recommended way is to store the image as a file not in the database and then store the path or enough of the path to uniquely identify the image in the database.
To store an image you have to store it as a BLOB based upon a byte[] (byte array);
However, using the Android SDK, there is a limitation that only images less than 2MB can be retrieved even though they can be saved.
Technically you could store the image as a hex, binary, octal string but that would be more complex, less efficient and even more restrictive.. So really you have to store it as a BLOB is not completely factual.
It's also actually pretty useless storing images (or any large files) with SQLite or most structured databases as there is little that you can do with the data query wise.
You actually save a BLOB via SQL using something like :-
INSERT INTO your_table VALUES(x'00FF01EF');
i.e. 00 (0) is the first byte, FF (255) the 2nd, 01 (01) the 3rd .........
note the above would only work for a table with a single column
However, the SQLiteDatabase insert convenience method does the conversion from the byte[] to the correct SQL (hex string) on your behalf.
So you'd typically use :-
ContentValues cv = new ContentValues();
cv.put("your_column",your_image_as_a_byte_array);
your_sqlitedatabase_object.insert("your_table",null,cv);
You retrieve the byte array from a Cursor (result of a query) using something along the lines of
your_retrieved_image_byte_array = your_cursor.getBlob(your_column_offset_as_an_int); //<<<<<<<<< CursorWindow full error if the row cannot fit into the CursorWindow which has 2MB limit
You may wish to have a look at How can I insert image in a sqlite database, as this goes into more detail and has code that stores both images and paths (either one is stored based upon the image size, less then 100k, then the image is stored, else the path is stored) and additionally retrieves the images into a ListView. Additionally, although not recommended this is a way of getting around the 2Mb limit How to use images in Android SQLite that are larger than the limitations of a CursorWindow?
Related
Can I add books to my SQLite database in android??
If yes, how?
I want to put the books on database because I've too many books to add to the android app and I don't want to make the size of the Application too much.
There's a limit of 1MB on internal assets due to dynamic decompression; the 1MB >limit also seems to apply to Cursor blobs but this doesn't seem to be >documented anywhere.
Generally you should avoid blobs in SQLite as they perform poorly; instead, >save the blob data as a file and store the location of the file in your DB
I won't recommend storing pdf flies in SQLite, you can just provide a simple link to download it to the user. but if you want to store it here you can do something like this.
First, you need to convert the pdf file into a byte array
import java.nio.file.*;
Path pdfFilePath = Paths.get("/file/path/your_file.pdf");
// Read file to byte array
byte[] pdfByteArray = Files.readAllBytes(pdfFilePath );
// Write byte array to file
Files.write(pdfFilePath , pdfByteArray);
You're looking for BLOB to store the data in android SQLite.
BLOB - The value is a blob of data, stored exactly as it was input.
Here's an example of making a table with two columns - an id and some data, which is a BLOB:
just for an example, you can create a table like this
CREATE TABLE t1 (id INTEGER PRIMARY KEY, data BLOB);
You can't do it. you cant store files in SQLite database. You will store your files in asserts folder.
I faced with the following situation. In my program I have to keep files in database. This database contains title of the article which keeps file and path to the file. All files are kept in Assets folder and are created manually. But what if I want to add files from the program itself. For example to create a special edittexts where user can write title and articles. How can I keep this data? I understand how to add title,entered by user,to database,it's easy. But what about the articles. I can't place them with file which were created manually,as Assets can't keep such files. I thought to add all full articles to database,but how can I add asset's files in such case?
Files (images, PDF'd. Word documents .........) are not structured data and serve little purpose being stored in the database (Full Text Search (FTS) an extension for SQLite is a different matter).
The recommended technique is to store some reference to the file (e.g. full path or perhaps file name (if all files are stored at a location that is discernible by the file name)) in the database. So when you locate/search and obtain a row you then use the file itself.
However, if the files average around about 100k or less then SQLite can actual be faster and thus it may performance wise, be better to store the files in the database.
Note the 100k based upon the link below.
35% Faster Than The Filesystem
You would store files as BLOB's (byte arrays). You read them into a byte array and on Android, assuming java and that the byte array is named my_byte_array and that the SQLiteDatabase is db then :-
ContentValues cv = new Contentvalues();
cv.put("FILE_COLUMN",my_byte_array);
........ other cv.put's for the other columns
long inserted_id = db.insert("The_Table",null,cv);
if (inserted_id < 1) {
.... code to handle row not inserted.
} else {
.... code to handle row inserted OK
}
WARNING
Files greater than 2M will be impossible to easily retrieve as a Cursor Window is limited to 2M of memory. Even 1M may well cause issues and may be unusable at some stage if the App needs to be backwardly compatible as I believe that Cursor window's were restricted to 1M (not sure when).
Retrieval from the database
To retrieve data from a BLOB you use the Cursor getBlob(column_offset) method, or generally better use the Cursor getColumnIndex(column_name) method to retrieve the column offset according to the column name. So if the Cursor is named csr then** my_other_byte_array = csr.getBlob(csr.getColumnIndex(column_name));**
Noting that you have to move to a valid row before using the getBlob method.
OVERVIEW:
I have a database that contains more than 128,000 records, and each record contains about 12 columns (8 string columns with lengths of about 1-2 words each column, and 4 columns containing reference or indices of 4 images respectively).
GOAL:
What I want basically is that when the user chooses a chapter contained in a spinner, the app shall retrieve the data relevant to the chapter chosen and display it on the screen (this is oversimplification though).
WHAT I DID but FAILED:
Creating a class for each column. (This taught me, in the hard way, the 64KB limit thing in Java.)
Creating an XML resource file for each column. (Failed because apparently, there's a limited number of ID, in effect resources, in an app)
WHAT I'M PLANNING TO (LEARN AND) DO:
Create an SQLite Database. (But I worry how would I prepopulate it with my data? Wouldn't this lead to the 64KB limit error?)
Create a text file for each column and store them as raw resources then retrieve them using input stream. (I, TBH, don't know what I'm talking about here. I picked this up while reading some sites yesterday).
So, what should I do?
(MORE DETAILS):
My app has a spinner containing 114 chapter titles
When the user chooses a chapter, the verses of the chapter will be displayed in the screen.
Each token (or say, word) of each verse is clickable.
Each token (including its details) represents one record in the database.
When the user clicks the token, the details about it will be displayed.
The details consist of 8 string columns, and 4 columns containing reference to the 4 images (image of a page of a dictionary).
The total aggregate size of the images is about 90 MB.
First of all you have to create Datebase from Server Side and you have to manage same Database from Android Side like SQLite.
When your application load first time, you have to copy all the data from server in chunks.(Manage OutOfMemoryError)
then you can use all the data from SQLite so it will work speedy.
After all you have to sync do sync process as i have mentioned here.
Thanks you.
I stored chunks of binary data (protobufs) in the sqlite database of an Android app without realizing that Android's Cursor can only hold a maximum of 1MB of data. I now know that I should have stored these binary blobs in files and only referenced the files in the sqlite database entries.
I need to upgrade the database (the app has been in use for a while) in order to move these binary chunks to files. The problem is that some user's data may have already exceeded the 1MB limit and I'm not able to retrieve it from the database (accessing the resulting Cursor for a single row that contains a large blob throws an IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialize before accessing data from it).
How do I retrieve the binary blobs that are greater than the 1MB Cursor limit that have been stored in the sqlite database?
You can read large blobs in pieces. First find out which ones need this treatment:
SELECT id, length(blobcolumn) FROM mytable WHERE length(blobcolumn) > 1000000
and then read chunks with substr:
SELECT substr(blobcolumn, 1, 1000000) FROM mytable WHERE id = 123
SELECT substr(blobcolumn, 1000001, 1000000) FROM mytable WHERE id = 123
...
You could also compile your own copy of SQLite and access either the BLOB stream I/O functions or the normal query functions of the C API with the NDK, but that would be too complex in this case.
CL. answer will only with blobs<5MB. If you tried to use it with blobs bigger than 5 megabytes you will still get the exception. To fetch large blobs you need to use a library called sqlite4java that uses native calls to the database without using cursors. Here is an example of using this library to fetch a large blob:
SQLiteConnection sqLiteConnection=null;
SQLiteStatement sqLiteStatement=null;
try
{
File databaseFile = context.getDatabasePath("database.db");
sqLiteConnection=new SQLiteConnection(databaseFile);
sqLiteConnection.open();
sqLiteStatement=sqLiteConnection.prepare("SELECT blob FROM table WHERE id=?");
sqLiteStatement.bind(1, id);
sqLiteStatement.step();
byte[] blob=sqLiteStatement.columnBlob(0);
}
finally
{
if(sqLiteStatement!=null)
sqLiteStatement.dispose();
if(sqLiteConnection!=null)
sqLiteConnection.dispose();
}
I have an Sqlite database insertion function
ContentValues values=new ContentValues();
values.put(CardTable.KEY_USERID, card_id);
values.put("id", some id);
values.put("namr", some name);
......
getContentResolver().insert(CardManagingProvider.CONTENT_URI_DETAIL, values);
My insert query is not working. Is it because one of the values in values is a long string (Base64-encoded form of an image)? Can any one please give me any suggestions?
You can see the length limits of SQLite here.
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.
You can determine if your Base64 exceeds those limits, however unlikely it may be.
I would recommend, however, not storing your Base64 string in the database. The larger your database is, the longer it takes for SQL statements to process. It's considered good practice to only store the URI of your image in the database, then use that URI to locate/load your image from disk/web.