I have used pre-existing database in my application which placed in assets folder and I am using that pre-existing structured for storing data. this is working fine in all the Android devices.
But Somehow it is not working in Android P beta version. When I unzip the database and store into the internal memory and when closed that database object, database file has being corrupted so, after closed the database only "android-metadata" table is left in that database file other tables has been removed automatically.
Please advice.!! what will be the cause. Here is my code
public void open() throws SQLException {
try {
boolean isExist = mDatabaseHelper.checkDataBase();
if (isExist == false) {
mDatabase = mDatabaseHelper.getWritableDatabase();
mDatabaseHelper.copyFromZipFile();
if (mDatabase.isOpen()) {
mDatabase.close();
}
}
mDatabase = mDatabaseHelper.getWritableDatabase();
} catch (Exception e) {
Logger.d(TAG, e.getMessage());
e.printStackTrace();
}
}
/**
* This method is used to close the dataHelper object.
*/
public void close() {
try {
if (mDatabase != null && mDatabase.isOpen())
mDatabase.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean checkDataBase() {
PACKAGE = mContext.getApplicationContext().getPackageName();
DB_PATH = DATA + PACKAGE + "/databases/";
Logger.d(TAG, DB_PATH);
File f = new File(DB_PATH + mDatabaseName);
return f.exists();
}
public void copyFromZipFile() throws IOException {
InputStream is = mContext.getAssets().open("xyz.zip");
// Path to the just created empty db
PACKAGE = mContext.getApplicationContext().getPackageName();
Logger.d(TAG, DB_PATH);
File outFile = new File(DB_PATH, mDatabaseName);
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFile.getAbsolutePath());
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));
try {
while (zis.getNextEntry() != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count;
while ((count = zis.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
baos.writeTo(myOutput);
}
} finally {
zis.close();
myOutput.flush();
myOutput.close();
is.close();
}
}
Related
I am copying SQLite Database from assets folder to android app. I am using below mentioned code. And it was working fine and I am doing my code smoothly. Suddenly, it stopped copying database to android app.
public class PreCreateDB {
public static void copyDB (Context context) {
try {
String destPath = "/data/data/"+ context.getPackageName()+ "/databases";
File f = new File(destPath);
if (!f.exists()) {
f.mkdir();
rawCopy(context.getAssets().open("dbname.db"), new FileOutputStream(destPath + "/dbname.db"));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void rawCopy(InputStream inputStream, OutputStream outputStream) throws IOException{
byte[] buffer = new byte[1024];
int length;
while ((length=inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
}
}
I found db in Device File Explorer and I see the following lines in it (not whole tables). Kindly help
SQLite format 3 # .�
� � W--ctableandroid_metadataandroid_metadataCREATE TABLE android_metadata (locale TEXT)
� � en_IN
I change my code to the following one, now it's working.
public static void copyDB (Context context) throws IOException {
try (SQLiteDatabase dbe = SQLiteDatabase.openDatabase("/data/data/com.app.example/databases/dbname.db", null, 0)) {
dbe.close();
} catch (Exception e) {
AssetManager am = context.getAssets();
OutputStream os = new FileOutputStream("/data/data/com.app.example/databases/dbname.db");
byte[] b = new byte[100];
int r;
InputStream is = am.open("dbname.db");
while ((r = is.read(b)) != -1) {
os.write(b, 0, r);
}
is.close();
os.close();
}
}
In my activity I create an object to copy a database from asset folder to app database, everything works fine in emulator but in the device, I get no such file or directory Error on
OutputStream os = new FileOutputStream(dbFile);
I have permission needed:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
I call in MainActivity:
db = new ExternalDB(this);
and in ExternalDB (Is SqliteOpenHelper):
ExternalDB(Context context){
super(context, DB_Name, null, DATABASE_VERSION);
mycontext = context;
AssetDatabaseOpenHelper adb = new AssetDatabaseOpenHelper(context,DB_Name);
db = adb.OpenDatabase();
}
And AssetDatabaseOpenHelper:
public class AssetDatabaseOpenHelper {
private static String DB_NAME;
private Context context;
AssetDatabaseOpenHelper(Context context, String DB_NAME){
this.context = context;
AssetDatabaseOpenHelper.DB_NAME = DB_NAME;
}
public SQLiteDatabase OpenDatabase(){
File dbFile = context.getDatabasePath(DB_NAME);
if(!dbFile.exists()){
try{
CopyDatabase(dbFile);
}
catch (IOException e){
throw new RuntimeException("Error Creating source database", e);
}
}
// copyDataBase();
return SQLiteDatabase.openDatabase(dbFile.getPath(),null,SQLiteDatabase.OPEN_READWRITE);
}
private void CopyDatabase(File dbFile) throws IOException{
InputStream is = context.getAssets().open(DB_NAME);
OutputStream os = new FileOutputStream(dbFile);
byte[] buffer = new byte[1024];
while(is.read(buffer)>0){
os.write(buffer);
}
os.flush();
os.close();
is.close();
}
}
As I Mentioned i get this error on this line:
OutputStream os = new FileOutputStream(dbFile);
CopyDatabase get's called when dbFile does not exist. Right? And then you tell the FileOutputStream to open the dbFile which we have established does not exist. Thus, no such file or directory Error. Seems legit, doesn't it?
The error is arising because the folder "databases" does not exist so the database cannot be copied
Try:
public SQLiteDatabase OpenDatabase() {
File dbFile = context.getDatabasePath(DB_NAME);
if (!dbFile.exists()) {
try {
//check if "databases" folder exists and create it if needed
File destDir = context.getDatabasePath(DB_NAME).getParentFile();
if(!destDir.exists()){
destDir.mkdirs();
}
CopyDatabase(dbFile);
} catch (IOException e) {
throw new RuntimeException("Error Creating source database", e);
}
} // copyDataBase();
return SQLiteDatabase.openDatabase(dbFile.getPath(), null, SQLiteDatabase.OPEN_READWRITE);
}
For Any One having same problem, Hard Coding database paths didn't work for me and finaly writing copy function like this solved my problem:
/**
* Copy database file from assets folder inside the apk to the system database path.
* #param context Context
* #param databaseName Database file name inside assets folder
* #param overwrite True to rewrite on the database if exists
* #return True if the database have copied successfully or if the database already exists without overwrite, false otherwise.
*/
private boolean copyDatabaseFromAssets(Context context, String databaseName , boolean overwrite) {
File outputFile = context.getDatabasePath(databaseName);
if (outputFile.exists() && !overwrite) {
return true;
}
outputFile = context.getDatabasePath(databaseName + ".temp");
outputFile.getParentFile().mkdirs();
try {
InputStream inputStream = context.getAssets().open(databaseName);
OutputStream outputStream = new FileOutputStream(outputFile);
// transfer bytes from the input stream into the output stream
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
// Close the streams
outputStream.flush();
outputStream.close();
inputStream.close();
outputFile.renameTo(context.getDatabasePath(databaseName));
} catch (IOException e) {
if (outputFile.exists()) {
outputFile.delete();
}
return false;
}
return true;
}
I had to create the folder databases first and then try to create database file.
from this answer: https://stackoverflow.com/a/29058717/4225644
Task: I want to copy selected files from A folder to B folder. Both folders are in the external storage.
Problem: It works perfectly fine, however, at some point it just stops copying files. For example, if I want to copy 500 files, it would copy only 110 files. Also I've noticed that I can't copy video files, it works only with images.
Code:
The method which I use to copy files:
private static void makeFileCopy(File source, File dest) throws IOException {
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(source);
os = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
}finally {
try {
if (is != null)
is.close();
if (os != null)
os.close();
}catch (IOException ex) {
ex.printStackTrace();
}
}
}
One more:
public static void copyFileList(Context context, List<MediaFile> contentList, File mediaFolder) {
if (contentList != null) {
ContentValues values=new ContentValues();
for (int index=0;index<contentList.size();index++) {
MediaFile mediaFile=contentList.get(index);
File file = new File(mediaFolder, mediaFile.mediaFile().getName());
boolean isVideo=mediaFile.getType()== MediaFile.Type.VIDEO;
if (!file.exists()) {
try {
if (!file.createNewFile()) {
continue;
}
FileUtils.makeFileCopy(mediaFile.getRealFile().getAbsoluteFile(), file);
} catch (IOException ex) {
ex.printStackTrace();
continue;
}
if (isVideo) {
values.put(MediaStore.Video.VideoColumns.DATA, file.getAbsolutePath());
context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
} else {
values.put(MediaStore.Images.ImageColumns.DATA, file.getAbsolutePath());
context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}
values.clear();
}
}
}
}
Thank you!
Finally, I've solved that problem. This is extremely stupid mistake I've made.
Solution: I wanted to make a copy of files which I already had in my destination folder, and by checking if (!file.exists()) it just did not pass. So, I've come up with the following code:
public static void copyFileList(Context context, List<MediaFile> contentList, File mediaFolder) {
if (contentList != null) {
ContentValues values=new ContentValues();
for (int index=0;index<contentList.size();index++) {
MediaFile mediaFile=contentList.get(index);
String fileName=mediaFile.mediaFile().getName();
boolean isVideo=mediaFile.getType()== MediaFile.Type.VIDEO;
File file = new File(mediaFolder, fileName);
//let a user to decide whether to create a copy of already existing files
if(!file.exists()) {
file=new File(mediaFolder,uniqueNameFor(fileName));
}
if(!file.exists()) {
try {
FileUtils.makeFileCopy(mediaFile.mediaFile().getAbsoluteFile(), file);
} catch (IOException ex) {
ex.printStackTrace();
continue;
}
if (isVideo) {
values.put(MediaStore.Video.VideoColumns.DATA, file.getAbsolutePath());
values.put(MediaStore.Video.VideoColumns.MIME_TYPE,mediaFile.getMimeType());
context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
} else {
values.put(MediaStore.Images.ImageColumns.DATA, file.getAbsolutePath());
values.put(MediaStore.Images.ImageColumns.MIME_TYPE,mediaFile.getMimeType());
context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}
}
values.clear();
}
}
}
Just create a unique name of the file.
Also I did change the copy method:
private static void makeFileCopy(File source, File dest) throws IOException {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(dest).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally {
try {
if (inputChannel != null)
inputChannel.close();
if (outputChannel != null)
outputChannel.close();
}catch (IOException ex) {
ex.printStackTrace();
}
}
}
Using channels is a little bit faster than using previous approach.
Check out 4 ways how to copy files here.
Thank you for help!
I am trying to copy a database named "adinpect" from the asset folder to the application databases folder, but it is not working...
Code (in main activity onCreate(), just for testing):
try {
String destPath = "/data/data/" + getPackageName() + "/databases";
File f = new File(destPath);
if (!f.exists()) {
f.mkdirs();
f.createNewFile();
//---copy the db from the assets folder into the databases folder---
CopyDB(getBaseContext().getAssets().open("adinspect"), new FileOutputStream(destPath + "/adinspect"));
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
public void CopyDB(InputStream inputStream, OutputStream outputStream) throws IOException {
//---copy 1K bytes at a time---
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
}//end copyDB
The "databases" folder is created but there in nothing in it, trying to access it by DDMS.
I do not get any errors.
Any suggestion?
Thanks
This code wlll help you to copy DB from assets folder.
You can check first if DB exists or not.
try{
// CHECK IS EXISTS OR NOT
SQLiteDatabase dbe = SQLiteDatabase.openDatabase("/data/data/"+getPackageName+"/databases/dbname.sqlite",null, 0);
dbe.close();
}
catch(Exception e)}
{
// COPY IF NOT EXISTS
AssetManager am = getApplicationContext().getAssets();
OutputStream os = new FileOutputStream("/data/data/"+getPackageName+"/databases/dbname.sqlite");
byte[] b = new byte[100];
int r;
InputStream is = am.open("dbname.sqlite");
while ((r = is.read(b)) != -1) {
os.write(b, 0, r);
}
is.close();
os.close();
}
When you use emulator your sqlite file is stored in a folder near your main application folder and you can download it. But this feature is not accessible in not rooted devices. How can I backup this existing sqlite file in SD Card programmatically?
I want to have a button in my application that stores this file in a special path in my SD Card. Is it possible?
Thanks,
You can try this, work for me, remember to get the WRITE_EXTERNAL_STORAGE permission in your manifest:
// Copy to sdcard for debug use
public static void copyDatabase(Context c, String DATABASE_NAME) {
String databasePath = c.getDatabasePath(DATABASE_NAME).getPath();
File f = new File(databasePath);
OutputStream myOutput = null;
InputStream myInput = null;
Log.d("testing", " testing db path " + databasePath);
Log.d("testing", " testing db exist " + f.exists());
if (f.exists()) {
try {
File directory = new File("/mnt/sdcard/DB_DEBUG");
if (!directory.exists())
directory.mkdir();
myOutput = new FileOutputStream(directory.getAbsolutePath()
+ "/" + DATABASE_NAME);
myInput = new FileInputStream(databasePath);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
} catch (Exception e) {
} finally {
try {
if (myOutput != null) {
myOutput.close();
myOutput = null;
}
if (myInput != null) {
myInput.close();
myInput = null;
}
} catch (Exception e) {
}
}
}
}
You can try following code,
String path = Environment.getExternalStorageDirectory().toString() + "/path";
File folder = new File( path );
if (!folder.exists())
{
folder.mkdirs();
}
File dbfile = new File( path + "/database.db" );
if ( !dbfile.exists() )
{
dbFile.createFile();
}
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
You can try this to copy a file:
public void copyFile(File in, File out) {
String DialogTitel = getString(R.string.daten_wait_titel);
String DialogText = getString(R.string.kopiervorgang_laeuft);
try {
// Dialogdefinition Prograssbar
final ProgressDialog dialog = new ProgressDialog(this) {
#Override
public boolean onSearchRequested() {
return false;
}
};
dialog.setCancelable(false);
dialog.setTitle(DialogTitel);
dialog.setIcon(R.drawable.icon);
dialog.setMessage(DialogText);
dialog.show();
new Thread(new MyCopyThread(in, out)) {
#Override
public void run() {
try {
FileChannel inChannel = new FileInputStream(
MyCopyThread.in).getChannel();
FileChannel outChannel = new FileOutputStream(
MyCopyThread.out).getChannel();
try {
System.out.println("KOPIEREN");
inChannel.transferTo(0, inChannel.size(),
outChannel);
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
setCopyError(false);
} catch (IOException e) {
setCopyError(true);
// throw e;
} finally {
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
dialog.dismiss();
// Abschlussarbeiten
if (useExternalSD == true) {
// Externe DB
moveDBtoExternFinish();
} else {
// Interne DB
moveDBtoInternFinish();
}
moveDBFinishHandler.sendMessage(moveDBFinishHandler
.obtainMessage());
} catch (Exception ex) {
}
}
}.start();
} catch (Exception exx) {
}
}
This is the code to get the filname of your internal db:
File interneDB = getApplicationContext().getDatabasePath(MY_DB_NAME);
Replace MY_DB_NAME with the name of your DB