Home > Blockchain >  How to read a file and store it in a variable?
How to read a file and store it in a variable?

Time:12-29

I am trying to develope an app which lets the user choose and read a csv file from his phone, so the app can set a variable with the chosen file content (string). This variable can then be used to set the text of a TextView.

I already was able to let the user of my app choose the desired file. I couldn't get the file content though. And I've already seen that onActivityResult and startActivityForResult are depreacated which means that a lot of tutorials are outdated. Plus I was not able to get a solution to my problem by the documentation enter image description here

This is what I have come up with so far for my ContentFragment.kt file. As you can see I already have a line for setting the TextView text to the content of a csv file which is located in the asset folder. That works great (here it is commented out - only there fyi), but I would like to do the same for the user's csv file:

package com.example.myapplication

import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.myapplication.databinding.FragmentContentBinding
import kotlinx.android.synthetic.main.fragment_content.*
import java.io.BufferedReader
import java.io.InputStreamReader

class ContentFragment : Fragment() {

    var _binding: FragmentContentBinding? = null
    val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        // Inflate the layout for this fragment
        _binding = FragmentContentBinding.inflate(inflater, container, false)

        val file = BufferedReader(InputStreamReader(resources.assets.open("Testfile.csv"))).use {
            it.readText()
        } // The variable is unused. This line of code only exists to demonstrate that the file_content.settext(file) in the TestButton click event is working.

        binding.TestButton.setOnClickListener {

            // file_content.setText(file) // <-- This line works

            val intent = Intent()
                .setType("*/*")
                .setAction(Intent.ACTION_GET_CONTENT)

            startActivity(Intent.createChooser(intent, "Select a file"))
        }

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }

    override fun onActivityResult(
        requestCode: Int, resultCode: Int, resultData: Intent?) {
        resultData?.data?.also { uri ->
            val file = BufferedReader(InputStreamReader(resources.assets.open(resultData.toString()))).use {
                it.readText()
            }

            file_content.setText(file)
        }
    }
}

This is the xml of the fragment:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ContentFragment"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@ id/TestButton"
        android:text="Import File"
        tools:ignore="MissingConstraints"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="In here the content of the file will appear."
        android:id="@ id/file_content"
        tools:ignore="MissingConstraints" />

</LinearLayout>

And here are more files, which are not so necessary:

MainActivity.kt:

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.myapplication.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding : ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="56dp"
        app:layout_constraintBottom_toBottomOf="parent">

        <fragment
            android:id="@ id/fragment"
            
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

CodePudding user response:

Replace:

            val file = BufferedReader(InputStreamReader(resources.assets.open(resultData.toString()))).use {
                it.readText()
            }

with:

            val file = BufferedReader(InputStreamReader(requireContext().contentResolver.openInputStream(uri))).use {
                it.readText()
            }

Note that your use of */* for the MIME type means that the user can choose non-text content. Consider using text/*.

CodePudding user response:

I was able to solve my problem by editing ContentFragment.kt. Now it works to let the user choose a csv-file and show its content in a textView.

package com.example.myapplication

import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import com.example.myapplication.databinding.FragmentContentBinding
import kotlinx.android.synthetic.main.fragment_content.*
import java.io.BufferedReader
import java.io.InputStreamReader

class ContentFragment : Fragment() {

    var _binding: FragmentContentBinding? = null
    val binding get() = _binding!!

    private val request = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
        if (uri != null) {
            val inputStream = requireContext().contentResolver.openInputStream(uri)
            val file = BufferedReader(InputStreamReader(inputStream)).use {
                it.readText()
            }
            file_content.setText(file)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        // Inflate the layout for this fragment
        _binding = FragmentContentBinding.inflate(inflater, container, false)

        binding.TestButton.setOnClickListener {

            val intent = Intent()
                .setType("*/*")
                .setAction(Intent.ACTION_GET_CONTENT)

            request.launch("*/*")
        }

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }
}
  • Related