How to import data into the app using Kotlin? - android

In my phone's Storage, There is a file which is "MyFile.sql". There are 200 records at the file. What should I do is to import those 200 records into the app.
First, I just Initialize
llUpdate.setOnClickListener { UpgradeDB(txtUpdate!!).execute("", "", "") }
After that, I start a method, I don't know why It found the file and read already, But it doesn't import to the app. Is this because I write return = null So it didn't import to the app?
override fun doInBackground(vararg params: String): String? {
val filename = "MyFile.sql"
val sdcard = Environment.getExternalStorageDirectory()
val file = File(sdcard, filename)
if (!file.exists()) isCancelled
var dbHelper: MyDBHelper? = null
dbHelper?.writableDatabase.use { db ->
var intTotalLine = 0
var intLine = 1
BufferedReader(FileReader(file)).useLines { _ -> intTotalLine++ }
BufferedReader(FileReader(file)).use { r ->
r.lineSequence().forEach {
if (it.isNotEmpty()) {
db?.execSQL(it)
publishProgress(String.format("Updating %s/%s records", intLine, intTotalLine))
intLine++
}
}
}
}
return null
}
Can you guys Please Help me to check where are the mistakes? Thanks in advance.

Related

Android how to change name file in device

I got files in device. And i want when click select one file and rename name file. But after rename, file become have not format file. How to rename file ?
fun renameFile(){
var file=listDownloadsFile.get(i).file
var filetwo=File("/storage/emulated/0/Download/",new_name)
var check:Boolean=file.renameTo(filetwo)
if(check){
Log.d("kkdkdk",check.toString())
}
else{
Log.d("kkdkdk",check.toString())
}
}
private fun getAllFileInDownload() {
var listDownloadsFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
.listFiles()
for (i in 0 until files.size) {
listDownloads.add(
FileData(
files[i],
false
)
)
}
} ```
you can try this:
fun renameFile(){
var file = listDownloadsFile.get(i).file
val oldName = file.nameWithoutExtension
val newPath = file.path.replace(oldName, new_name).trim()
val filetwo = File(newPath)
if (filetwo.exists()) {
//show a message file exited
} else {
val check = renameFile(file, filetwo)
if(check){
Log.d("kkdkdk",check.toString())
}
else{
Log.d("kkdkdk",check.toString())
}
}
}
private fun rename(from: File, to: File): Boolean {
return from.parentFile.exists() && from.exists() && from.renameTo(to)
}

Android 11 : How to write at 30 files per seconds on removable storage (ssd drive on usb)

I want to save images taken from my app directly to a ssd drive (removable storage) plugged in my device.
The issue I have now, is that with Android 11, I didn't manage to get the path of this storage, and so I can't write the files...
I tried use Storage Access Framework to ask the user to specify the path directly for each images but I can't use this solution as I need to write 30 images per seconds and it kept asking the user select an action on the screen.
This application is only for internal use, so I can grant all the permission without any Google deployment politics issues.
Can anybody help me, i'm so desperate...
So here's my code, I can write on a folder the user choose with SAF. Still have speed issue using DocumentFile.createFile function.
package com.example.ssdwriter
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.*
import android.util.Log
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.documentfile.provider.DocumentFile
class MainActivity : AppCompatActivity() {
private val TAG = "SSDActivity"
private val CONTENT = ByteArray(2 * 1024 * 1024)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
grantDirectoryAccess()
}
private fun grantDirectoryAccess() {
val treeUri = contentResolver.persistedUriPermissions
if (treeUri.size > 0) {
Log.e(TAG, treeUri.size.toString())
startWriting(treeUri[0].uri)
} else {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
var resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
result.data?.data?.let {
contentResolver.takePersistableUriPermission(
it,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
}
startWriting(result.data?.data!!)
}
}
resultLauncher.launch(intent)
}
}
private fun startWriting(uri: Uri) {
var handlerThread = HandlerThread("writer")
handlerThread.start()
var counter = 0
val handler = Handler(handlerThread.looper)
val runnableCode: Runnable = object : Runnable {
override fun run() {
Log.e(TAG, "Writing File $counter")
createFile(uri, counter++)
Log.e(TAG, "File $counter written ")
if(counter <= 150){
handler.postDelayed(this, 33)
}
}
}
handler.post(runnableCode)
}
private fun createFile(treeUri: Uri, counter: Int) {
val dir = DocumentFile.fromTreeUri(this, treeUri)
val file = dir!!.createFile("*/bmp", "Test$counter.bmp")
if (file != null) {
var outputStream = contentResolver.openOutputStream(file.uri)
if (outputStream != null) {
outputStream.write(CONTENT)
outputStream.flush()
outputStream.close()
}
}
}
}
If anyone got some clues to make this faster, it would be great !

Multiple files are not getting copied to local directory in Android

I am using below code to save image data into local directory from Uris obtained through pick intent.
private fun sendImages(uriString: String, messageBody: String, uriList: ArrayList<Uri>) {
val pathList = mutableListOf<String>()
val fileNameList = mutableListOf<String>()
var fieSize = 0
var multiSize = 0
if(uriList.isEmpty() && uriString.isNotEmpty())
uriList.add(Uri.parse(uriString))
val localId: String = "localId"
for(i in 0 until uriList.size) {
val uri = uriList[i]
val path = FileUtils.getPath(application, uri)!!
val fullName = path.substring(path.lastIndexOf("/") + 1)
val name = "some function call that returns unique name for file"
val file = File(requireActivity().applicationContext.filesDir, localId + name)
file.createNewFile()
var bitmapdata: ByteArray? = null
var inputStream: InputStream? = null
try {
val ei = ExifInterface(path)
val orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
var bitmap: Bitmap? = null
bitmap = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(requireActivity().applicationContext.contentResolver, uri))
}
else MediaStore.Images.Media.getBitmap(requireActivity().applicationContext.contentResolver, uri)
val newBitmap = FunctionUtil.rotateImage(bitmap, orientation)
bitmapdata = FileUtils.getCompressedBitmapForUpload(newBitmap!!)
FunctionUtil.recycleBitmap(newBitmap)
} catch (e: Exception) {
return
}
}
requireActivity().applicationContext.openFileOutput(file.name, Context.MODE_PRIVATE).use {
it.write(bitmapdata)
}
val localPath = FunctionUtil.getMediaStorePath(requireActivity().application)
val completePath = requireActivity().application.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)!!
var outFile =File(localPath+"/"+file.name)
org.apache.commons.io.FileUtils.copyFile(file,outFile)
Logger.log("PATH ${ outFile.absolutePath} ${ outFile.path}")
pathList.add(outFile.absolutePath)
fileNameList.add(file.name)
//... Do something with this data
}
}
In the same code, if single file is copied to local directory, it is getting saved & i am able to send it . But whenever i try to save multiple files, the files are becoming empty when i try to send them.
I am not able to find what issue is there. Please help
Some Android phones will encounter such a problem :
the file does exist, but the 'fd' returned by the 'c++ open()' method is -1, and the 'strerror' showing 'No such file or directory".
The phones I have come across are as follows:
vivo
V2055A V2073A V2241A
huawei
GIA-AN00 JLH-AN00 CMA-AN00 HPB-AN00 NTN-AN20 CMA-AN40
oppo
LE2110
In the source code of the Android System, a similar phenomenon can also be found :
The above is a comment added in 2017, and only the common 'bmp' and 'ico' formats are written.
In face, this problem also occurs with pictures in 'heif/heic' format.
Finally,
Using 'FileInputStream' will be ok.

Android Load html file to local server

I want to make Android App, which will run its local HTTP server. Through this server I want to load index.html to WebView. index.html is not working on its own. It is web app and has to be initialized on localhost. Also it is running other .js files inside assets folder.
To run this before I used python HTTP server and run it in browser from there.
I used Ktor library to create simple HTTP server but it shows just blank page. I don't know if I'm on right path with this solution at all.
My entire App:
import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import io.ktor.application.install
import io.ktor.features.ContentNegotiation
import io.ktor.gson.gson
import io.ktor.http.content.default
import io.ktor.routing.routing
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.web_view)
initHttpServer()
initWebViewContent()
}
private fun initHttpServer(){
embeddedServer(Netty, 8080) {
install(ContentNegotiation) {
gson {}
}
routing {
default("/app/src/main/assets/index.html")
}
}.start(wait = true)
}
#SuppressLint("SetJavaScriptEnabled")
private fun initWebViewContent(){
webView.apply {
loadUrl("http://127.0.0.1:8080")
webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
view.loadUrl(url)
return false
}
}
settings.apply {
setSupportZoom(true)
builtInZoomControls = true
displayZoomControls = false
javaScriptEnabled = true
javaScriptCanOpenWindowsAutomatically = true
}
}
}
}
Ok I dont need HTTP server - index.html can be loaded as:
webView.loadUrl("file:///android_asset/index.html")
index.html is placed inside /app/src/main/assets/ subfolder which is default asset folder for Android project.
class AssertFileContent(
private val context: Context,
private val path: String
) : OutgoingContent.ReadChannelContent() {
override val contentLength: Long?
get() {
val inputStream = context.assets.open(path)
val available = inputStream.available()
inputStream.close()
return available.toLong()
}
override fun readFrom() = context.assets.open(path).toByteReadChannel()
}
private const val pathParameterName = "static-content-path-parameter"
fun Route.assetsFiles(context: Context, path: String = "") {
get("{$pathParameterName...}") {
val relativePath =
call.parameters.getAll(pathParameterName)
?.joinToString(File.separator, prefix = path)
?: return#get
try {
val content =
AssertFileContent(context, relativePath)
call.respond(content)
} catch (e: FileNotFoundException) {
call.respond(HttpStatusCode.NotFound)
}
}
}
// Application.routing
static("/") {
assetsFiles(context, "/webapp")
}
// assets folder structure
webapp
- index.html
You are trying to serve using a file that doesn't exist. assets folder are packaged into APK and you can only access it through AssetManager. Ktor doesn't know about AssetManager and uses standard facilities to access local files.
I suggest copying all the web resources to internal storage and serve from there (filesDir is the path to the root directory):
private fun copyWebResources() {
val files = assets.list("web")
files?.forEach { path ->
val input = assets.open("web/$path")
val outFile = File(filesDir, path)
val outStream = FileOutputStream(outFile)
outStream.write(input.readBytes())
outStream.close()
input.close()
}
}
For the server, you can use the following setup:
embeddedServer(Netty, 3333) {
install(ContentNegotiation) {
gson {}
}
routing {
static("static") {
files(filesDir)
}
}
}
Here is example of assets folder structure:
web
index.html
script.js
Example URL for loadUrl is http://127.0.0.1:3333/static/index.html.
Also, there is a full sample project.
I see that the OP problem is fixed with local access but for anyone who genuinely want to have a web server on an android device to get to from other devices, this is what I ended up doing.
I read the html from asset using AssetManager and then serve that up with ktor:
routing {
get("/") {
val html = application.assets.open("index.html").bufferedReader()
.use {
it.readText()
}
call.respondText(html, ContentType.Text.Html)
}
}
private fun copyFile(context: Context,filePath: String){
val file = context.assets.open(filePath)
val outFile = File(context.filesDir, filePath)
val outStream = FileOutputStream(outFile)
file.copyTo(outStream)
outStream.close()}
private fun copyDir(context: Context,path:String){
val assets = context.assets
val asset = assets.list(path)
asset?.forEach { list ->
val listPath = "$path/$list"
//文件夹
if(!list.toString().contains(".")){
println("Dir::$listPath")
File(context.filesDir.path,listPath).mkdir()
copyDir(context,listPath)
return
}
println("File::$listPath")
copyFile(context,listPath)
}}
fun main(){
File(context.filesDir.path,"www").mkdir()
copyDir(context,path = "www")}

File byte error in kotlin. How to transfer correctly?

I want to Transfer file with tcp client to server, but image file has been wrong.
My client code is
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream
import org.msgpack.core.MessageBufferPacker
import org.msgpack.core.MessagePack
import org.msgpack.core.MessageUnpacker
import java.io.*
import java.net.Socket
import java.util.*
fun main(args: Array<String>) {
fileClient("localhost",1988,"fruit.jpg")
}
class fileClient (host:String, port:Int, file:String){
var s : Socket ?= null
var out = ByteArrayOutputStream()
var msg : MessageBufferPacker = MessagePack.newDefaultBufferPacker()
init {
try {
s = Socket(host,port)
sendFile(file)
}catch (e:Exception){
e.printStackTrace()
}
}
#Throws(IOException::class)
fun sendFile(file: String) {
val dos = DataOutputStream(s!!.getOutputStream())
val buffer = ByteArray(4096)
val filebytes = File(file).readBytes()
var msgdata = ByteOutputStream()
msg.packString(file)
msg.packBinaryHeader(filebytes.size)
msg.writePayload(filebytes)
msg.close()
val data = msg.toByteArray()
val datasize = data.size
val ins = ByteArrayInputStream(data)
dos.writeInt(datasize)
while (ins.read(buffer) > 0) {
dos.write(buffer)
}
dos.close()
}
}
And my server code is
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream
import org.msgpack.core.MessagePack
import org.msgpack.core.MessageUnpacker
import java.awt.List
import java.io.*
import java.net.ServerSocket
import java.net.Socket
import java.text.SimpleDateFormat
import java.util.*
fun main(args: Array<String>) {
var fs = FileServer(1988)
fs.start()
}
class FileServer(port: Int) : Thread() {
private var ss: ServerSocket? = null
var fileRealName : String ?= null
init {
try {
ss = ServerSocket(port)
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun run() {
while (true) {
try {
val clientSock = ss!!.accept()
saveFile(clientSock)
} catch (e: IOException) {
e.printStackTrace()
}
}
}
#Throws(IOException::class)
private fun saveFile(clientSock: Socket) {
var msgList = ArrayList<Any>()
val dis = DataInputStream(clientSock.inputStream)
val msgdata = ByteOutputStream()
val buffer = ByteArray(4096)
var read = 0
while (true) {
val datalen = dis.readInt() // data length
if(datalen!= null && datalen >0){
var finaldata = ByteArray(datalen)
var process = 0;
while (process <= datalen) {
read = dis.read(buffer)
if (read < 0) {
return
}
msgdata.write(buffer)
process += 4096
}
println(process.toString() + " "+ datalen.toString())
var allData = msgdata.toByteArray().slice(0..datalen).toByteArray()
unpackByte(allData)
}
}
msgdata.close()
dis.close()
}
private fun unpackByte(data:ByteArray){
var unpacker : MessageUnpacker = MessagePack.newDefaultUnpacker(data)
var fileName = unpacker.unpackString().toString()
var filesize = unpacker.unpackBinaryHeader()
var buffer = ByteArray(filesize)
unpacker.readPayload(buffer)
var fos = FileOutputStream(fileName)
fos.write(buffer)
fos.close()
unpacker.close()
}
}
And a file what I want to transfer is
but after transfer, image on server is like this.
How can I transfer this file correctly?
I didn't succeeded in reproducing your problem. However I think I've found the bug that may be causing corrupted file transfer.
In your server code there's an infinite loop that returns immediately out of method leaving the rest of method unreachable. This is the clean-up code that closes connections and streams. Quite possibly the OutputStream was not properly closed and this is the cause of corrupted file write.
That's how the server code should look like:
val datalen = dis.readInt() // data length
if (datalen > 0) {
var finaldata = ByteArray(datalen)
var process = 0;
while (process <= datalen) {
read = dis.read(buffer)
if (read < 0) {
break
}
msgdata.write(buffer)
process += 4096
}
println(process.toString() + " " + datalen.toString())
val allData = msgdata.toByteArray().slice(0..datalen).toByteArray()
unpackByte(allData)
}
msgdata.close()
dis.close()
while loop is unnecessary. Also you probably should just break the loop, not return from function.
P.S.
Have you considered using IOUtils to handle all the IO read/writes? Half of your code could be replaced with just a few lines of code using this library.

Categories

Resources