0

I'm trying to read from a file in kotlin using the File class. It's just a simple txt file with a list of names with each name occupying an independent row. This is my project structure: enter image description here

and here's my function for pulling out a name depending on the day of the year:

private fun getNameOfTheDay(): String {
        val cal = Calendar.getInstance()
        val day = cal[Calendar.DATE]

        return File("data${File.separator}names.txt")
            .bufferedReader()
            .lineSequence()
            .elementAt(day - 1)
    }

I keep on getting a FileNotFound exception so I would assume that my file path is somehow wrong... What am I doing wrong here? Sorry for the dumb question, I'm still learning. By the way the function shown above is called from the MainActivity. Thanks in Advance!

Nathan Kim
  • 344
  • 1
  • 9

2 Answers2

2

Filenames can be absolute or relative. Absolute filenames start from the top level (e.g. the root directory on Unix-like filesystems, which Macs have; or a drive letter on Windows), and so specify the filename unambiguously. Relative filenames don't, and so give a file in (or in relation to) the current working directory.

In this case, data/names.txt is a relative filename. It assumes that the current directory has a subdirectory called data, and refers to a file in that.

However, the file is actually in the directory app/src/main/java/com/example/mynameis/data/ within your project — so this would only work if the current directory was /<pathToYourProject>/app/src/main/java/com/example/mynameis/, which is highly unlikely! So that probably explains the failure.

I don't know about Android projects, but in normal JVM projects the standard practice is to put data files in a src/main/resources/ directory. Gradle (or Maven) knows to copy them into the classpath when building the project. You would then load it from the classpath, e.g. with:

javaClass.getResource("data/names.txt").readText()

See e.g. this question for more details and variations.

The advantage of loading from the classpath instead of a file path is that you don't need to know exactly where the file is; it could be loose on the filesystem, or bundled into a jar or other archive (even compressed), with ways to select between different versions depending on the run profile — all completely transparent to your code.

As I said, I don't know Android, and can't find any direct answers on StackOverflow. (This question seems to suggest using a android.resource:// URI, but I don't know if that would apply here.) Maybe these external sites can give you some hints.

gidds
  • 16,558
  • 2
  • 19
  • 26
0

You should try "data\names.txt". Oftentimes slashes don't work for file paths.

Timon
  • 16
  • 1
  • Woops, yeah sorry, I forgot to mention that I was on Mac. Changed the / to File.Separator. – Nathan Kim Feb 28 '22 at 21:53
  • 1
    `/` generally works fine on Macs (this century, anyway). Of course, `File.separator` is safer and should work on even more platforms, but I doubt that explains the problem here. – gidds Feb 28 '22 at 23:05
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 01 '22 at 06:45