Export SQLite database

This commit is contained in:
Markus Fisch
2020-04-27 20:47:20 +02:00
parent 256183b4aa
commit 607e1324ed
17 changed files with 182 additions and 122 deletions
@@ -0,0 +1,85 @@
package de.markusfisch.android.binaryeye.data
import android.content.Context
import android.database.Cursor
import de.markusfisch.android.binaryeye.app.writeExternalFile
fun exportCsv(
context: Context,
name: String,
cursor: Cursor,
delimiter: String
) {
if (!cursor.moveToFirst()) {
return
}
val columns = arrayOf(
Database.SCANS_DATETIME,
Database.SCANS_FORMAT,
Database.SCANS_CONTENT,
Database.SCANS_ERROR_CORRECTION_LEVEL,
Database.SCANS_ISSUE_NUMBER,
Database.SCANS_ORIENTATION,
Database.SCANS_OTHER_META_DATA,
Database.SCANS_PDF417_EXTRA_METADATA,
Database.SCANS_POSSIBLE_COUNTRY,
Database.SCANS_SUGGESTED_PRICE,
Database.SCANS_UPC_EAN_EXTENSION
)
val indices = columns.map {
cursor.getColumnIndex(it)
}
val contentIndex = cursor.getColumnIndex(Database.SCANS_CONTENT)
val rawIndex = cursor.getColumnIndex(Database.SCANS_RAW)
writeExternalFile(context, name, "text/csv") { outputStream ->
outputStream.write(
columns.joinToString(
delimiter,
postfix = "\n"
).toByteArray()
)
do {
var deviation: Pair<Int, String>? = null
if (cursor.getString(contentIndex)?.isEmpty() == true) {
deviation = Pair(
contentIndex,
cursor.getBlob(rawIndex).toHexString()
)
}
outputStream.write(
cursor.toCsvRecord(indices, delimiter, deviation)
)
} while (cursor.moveToNext())
}
}
private fun ByteArray.toHexString(): String {
val hex = StringBuilder()
for (i in this.indices) {
hex.append(String.format("%02X", this[i]))
}
return hex.toString()
}
private fun Cursor.toCsvRecord(
indices: List<Int>,
delimiter: String,
deviation: Pair<Int, String>?
): ByteArray {
val sb = StringBuilder()
indices.forEach {
val value = if (deviation?.first == it) {
deviation.second
} else {
this.getString(it)
}
sb.append(value?.quoteAndEscape() ?: "")
sb.append(delimiter)
}
sb.append("\n")
return sb.toString().toByteArray()
}
private fun String.quoteAndEscape() = "\"${this
.replace("\n", " ")
.replace("\"", "\"\"")}\""
@@ -184,7 +184,7 @@ class Database {
}
private class OpenHelper(context: Context) :
SQLiteOpenHelper(context, "history.db", null, 4) {
SQLiteOpenHelper(context, FILE_NAME, null, 4) {
override fun onCreate(db: SQLiteDatabase) {
createScans(db)
}
@@ -207,6 +207,7 @@ class Database {
}
companion object {
const val FILE_NAME = "history.db"
const val SCANS = "scans"
const val SCANS_ID = "_id"
const val SCANS_DATETIME = "_datetime"
@@ -1,85 +1,39 @@
package de.markusfisch.android.binaryeye.data
import android.content.Context
import android.database.Cursor
import android.app.Activity
import android.os.Environment
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.hasWritePermission
import de.markusfisch.android.binaryeye.app.writeExternalFile
import de.markusfisch.android.binaryeye.widget.toast
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
import java.io.FileInputStream
fun exportCsv(
context: Context,
name: String,
cursor: Cursor,
delimiter: String
) {
if (!cursor.moveToFirst()) {
fun exportDatabase(activity: Activity, fileName: String) {
if (!hasWritePermission(activity)) {
return
}
val columns = arrayOf(
Database.SCANS_DATETIME,
Database.SCANS_FORMAT,
Database.SCANS_CONTENT,
Database.SCANS_ERROR_CORRECTION_LEVEL,
Database.SCANS_ISSUE_NUMBER,
Database.SCANS_ORIENTATION,
Database.SCANS_OTHER_META_DATA,
Database.SCANS_PDF417_EXTRA_METADATA,
Database.SCANS_POSSIBLE_COUNTRY,
Database.SCANS_SUGGESTED_PRICE,
Database.SCANS_UPC_EAN_EXTENSION
val dbFile = File(
Environment.getDataDirectory(),
"//data//${activity.packageName}//databases//${Database.FILE_NAME}"
)
val indices = columns.map {
cursor.getColumnIndex(it)
if (!dbFile.exists()) {
activity.toast(R.string.error_no_content)
return
}
val contentIndex = cursor.getColumnIndex(Database.SCANS_CONTENT)
val rawIndex = cursor.getColumnIndex(Database.SCANS_RAW)
writeExternalFile(context, name, "text/csv") { outputStream ->
outputStream.write(
columns.joinToString(
delimiter,
postfix = "\n"
).toByteArray()
)
do {
var deviation: Pair<Int, String>? = null
if (cursor.getString(contentIndex)?.isEmpty() == true) {
deviation = Pair(
contentIndex,
cursor.getBlob(rawIndex).toHexString()
)
}
outputStream.write(
cursor.toCsvRecord(indices, delimiter, deviation)
)
} while (cursor.moveToNext())
}
}
private fun ByteArray.toHexString(): String {
val hex = StringBuilder()
for (i in this.indices) {
hex.append(String.format("%02X", this[i]))
}
return hex.toString()
}
private fun Cursor.toCsvRecord(
indices: List<Int>,
delimiter: String,
deviation: Pair<Int, String>?
): ByteArray {
val sb = StringBuilder()
indices.forEach {
val value = if (deviation?.first == it) {
deviation.second
} else {
this.getString(it)
GlobalScope.launch {
val message = writeExternalFile(
activity,
fileName,
"application/vnd.sqlite3"
) {
FileInputStream(dbFile).copyTo(it)
}
GlobalScope.launch(Main) {
activity.toast(message)
}
sb.append(value?.quoteAndEscape() ?: "")
sb.append(delimiter)
}
sb.append("\n")
return sb.toString().toByteArray()
}
private fun String.quoteAndEscape() = "\"${this
.replace("\n", " ")
.replace("\"", "\"\"")}\""
@@ -23,6 +23,7 @@ import de.markusfisch.android.binaryeye.adapter.ScansAdapter
import de.markusfisch.android.binaryeye.app.*
import de.markusfisch.android.binaryeye.data.Database
import de.markusfisch.android.binaryeye.data.exportCsv
import de.markusfisch.android.binaryeye.data.exportDatabase
import de.markusfisch.android.binaryeye.view.setPadding
import de.markusfisch.android.binaryeye.view.setWindowInsetListener
import de.markusfisch.android.binaryeye.view.useVisibility
@@ -333,24 +334,30 @@ class HistoryFragment : Fragment() {
}
private fun askToExportToFile(context: Context) = scope.launch {
val ac = activity ?: return@launch
progressView.useVisibility {
if (!hasWritePermission(activity)) {
if (!hasWritePermission(ac)) {
return@useVisibility
}
val delimiters = context.resources.getStringArray(
R.array.csv_delimiters_values
val options = context.resources.getStringArray(
R.array.export_options_values
)
val delimiter = alertDialog<String>(context) { resume ->
setTitle(R.string.csv_delimiter)
setItems(R.array.csv_delimiters_names) { _, which ->
resume(delimiters[which])
setTitle(R.string.export_as)
setItems(R.array.export_options_names) { _, which ->
resume(options[which])
}
} ?: return@useVisibility
val isCsv = delimiter != "sql"
val name = withContext(Dispatchers.Main) {
activity.askForFileName(suffix = ".csv")
ac.askForFileName(if (isCsv) ".csv" else ".db")
} ?: return@useVisibility
db.getScansDetailed(filter)?.use { cursor ->
exportCsv(context, name, cursor, delimiter)
if (isCsv) {
db.getScansDetailed(filter)?.use { cursor ->
exportCsv(context, name, cursor, delimiter)
}
} else {
exportDatabase(ac, name)
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
android:icon="@drawable/ic_action_search"
android:title="@string/search_scan"
material:actionViewClass="android.support.v7.widget.SearchView"
material:showAsAction="collapseActionView|ifRoom"/>
material:showAsAction="collapseActionView|always"/>
<item
android:id="@+id/export_history"
android:icon="@drawable/ic_action_export"
+4 -3
View File
@@ -79,9 +79,10 @@
<string name="search_web">Suche im Internet</string>
<string name="search_scan">Code suchen</string>
<string name="export_to_file">In Datei exportieren</string>
<string name="csv_delimiter">Welches Trennzeichen soll genutzt werden (CSV-Datei)?</string>
<string name="delimiter_comma">Komma</string>
<string name="delimiter_semicolon">Semikolon</string>
<string name="export_as">Exportieren als?</string>
<string name="export_csv_comma">CSV mit Kommas</string>
<string name="export_csv_semicolon">CSV mit Semikolons</string>
<string name="export_database">SQLite Datenbank exportieren</string>
<string name="saved_in_downloads">In den Downloads gespeichert</string>
<string name="rotate_image_cw">Bild im Uhrzeigersinn rotieren</string>
<string name="pick_file">Bilddatei auswählen</string>
+4 -3
View File
@@ -79,9 +79,10 @@
<string name="search_web">Search the web</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">Export to file</string>
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
<string name="delimiter_comma">Comma</string>
<string name="delimiter_semicolon">Semicolon</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">Saved in downloads</string>
<string name="rotate_image_cw">Rotate image clockwise</string>
<string name="pick_file">Pick image file</string>
+4 -3
View File
@@ -79,9 +79,10 @@
<string name="search_web">Keresés a weben</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">Exportálás fájlba</string>
<string name="csv_delimiter">Milyen mezőelválasztót kell használni (CSV-fájl)?</string>
<string name="delimiter_comma">Vessző</string>
<string name="delimiter_semicolon">Pontosvessző</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">Elmentve a letöltésekbe</string>
<string name="rotate_image_cw">Kép forgatása jobbra</string>
<string name="pick_file">Képfájl kiválasztása</string>
+4 -3
View File
@@ -78,9 +78,10 @@
<string name="search_web">Cari secara daring</string>
<string name="search_scan">Cari pindaian</string>
<string name="export_to_file">Ekspor ke berkas</string>
<string name="csv_delimiter">Karakter pemisah apa yang harus digunakan (Berkas-CSV)?</string>
<string name="delimiter_comma">Koma</string>
<string name="delimiter_semicolon">Titik koma</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">Simpan di dalam unduhan</string>
<string name="rotate_image_cw">Putar gambar searah jarum jam</string>
<string name="pick_file">Pilih berkas gambar</string>
+4 -3
View File
@@ -79,9 +79,10 @@
<string name="search_web">Cerca nel web</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">Esporta su file</string>
<string name="csv_delimiter">Quale delimitatore usare (File-CSV)?</string>
<string name="delimiter_comma">Virgola</string>
<string name="delimiter_semicolon">Punto e virgola</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">Salvato nei download</string>
<string name="rotate_image_cw">Ruota immagine in senso orario</string>
<string name="pick_file">Scegli file immagine</string>
+4 -3
View File
@@ -75,9 +75,10 @@
<string name="search_web">Het net doorzoeken</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">Naar bestand exporteren</string>
<string name="csv_delimiter">Wat voor separator wil je gebruiken (CSV-bestand)?</string>
<string name="delimiter_comma">Komma</string>
<string name="delimiter_semicolon">Kommapunt</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="error_saving_binary_data">Kon bestand niet opslaan</string>
<string name="open_with_url">Niet herkende data met URL openen</string>
<string name="pick_list_separator">Hoe de lijstonderdelen te separeren?</string>
+4 -3
View File
@@ -79,9 +79,10 @@
<string name="search_web">Search the web</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">Export to file</string>
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
<string name="delimiter_comma">Comma</string>
<string name="delimiter_semicolon">Semicolon</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">Saved in downloads</string>
<string name="rotate_image_cw">Rotate image clockwise</string>
<string name="pick_file">Pick image file</string>
+4 -3
View File
@@ -75,9 +75,10 @@
<string name="search_web">Search the web</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">Export to file</string>
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
<string name="delimiter_comma">Comma</string>
<string name="delimiter_semicolon">Semicolon</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">Saved in downloads</string>
<string name="rotate_image_cw">Rotate image clockwise</string>
<string name="pick_file">Pick image file</string>
+4 -3
View File
@@ -78,9 +78,10 @@
<string name="search_web">在互联网中搜索</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">导出为CSV文件</string>
<string name="csv_delimiter">使用哪个分隔符 (CSV-文件)?</string>
<string name="delimiter_comma">逗号</string>
<string name="delimiter_semicolon">分号</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">已保存到下载目录</string>
<string name="rotate_image_cw">旋转图片</string>
<string name="pick_file">选择图片文件</string>
+4 -3
View File
@@ -78,9 +78,10 @@
<string name="search_web">Search the web</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">Export to file</string>
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
<string name="delimiter_comma">Comma</string>
<string name="delimiter_semicolon">Semicolon</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">Saved in downloads</string>
<string name="rotate_image_cw">Rotate image clockwise</string>
<string name="pick_file">Pick image file</string>
+6 -4
View File
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="csv_delimiters_names">
<item>@string/delimiter_comma</item>
<item>@string/delimiter_semicolon</item>
<string-array name="export_options_names">
<item>@string/export_csv_comma</item>
<item>@string/export_csv_semicolon</item>
<item>@string/export_database</item>
</string-array>
<string-array name="csv_delimiters_values">
<string-array name="export_options_values">
<item>,</item>
<item>;</item>
<item>sql</item>
</string-array>
</resources>
+4 -3
View File
@@ -79,9 +79,10 @@
<string name="search_web">Search the web</string>
<string name="search_scan">Search scan</string>
<string name="export_to_file">Export to file</string>
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
<string name="delimiter_comma">Comma</string>
<string name="delimiter_semicolon">Semicolon</string>
<string name="export_as">Export as?</string>
<string name="export_csv_comma">CSV with commas</string>
<string name="export_csv_semicolon">CSV with semicolons</string>
<string name="export_database">Export SQLite database</string>
<string name="saved_in_downloads">Saved in downloads</string>
<string name="rotate_image_cw">Rotate image clockwise</string>
<string name="pick_file">Pick image file</string>