0

I am fairly new to Android + Kotlin, however I am wondering if there is a faster way to read a text (.pgn) file and mark pointers to places in the file for later reference.

At the moment I am using RandomAccessFile however it is incredible slow for a process that should be extremely quick.

This is my code at the moment:

private fun loadPGN() {
    try {
            val selectedPGN = File((context as MainActivity).filesDir, "mygames.pgn")
            val raf = RandomAccessFile(selectedPGN, "r")
            val length = raf.length()
            raf.seek(0)
            charPosition = raf.filePointer

            while (charPosition < length) {
                val str : String = raf.readLine()
                if (str.contains("[Event ")) {
                    mutableListEvent += charPosition
                    findMoves = true
                }
                if (findMoves && ((str.startsWith(str.filter { it.isDigit() }) && !str.startsWith("[")) || str.startsWith("{ "))) {
                    mutableListMoves += charPosition
                    findMoves = false
                }
                charPosition = raf.filePointer
            }

            for (i in 0 until mutableListEvent.size) {
                val event = if (mutableListEvent[i] != mutableListEvent[mutableListEvent.size - 1]) mutableListEvent[i + 1] else length
                val moves = mutableListMoves[i]
                raf.seek(mutableListEvent[i])
                eventStr = raf.readLine().removeRange(0,8).replace("\"]", "")
                eventMutableList.add(eventStr)
                difference += (event - moves)
                headerLength += (mutableListMoves[i] - mutableListEvent[i])
                raf.seek(moves)
                val byteArray = ByteArray(difference[i].toInt())
                raf.readFully(byteArray)
                val string = String(byteArray)
                var stringEdited = String(byteArray).replace("\n","")
                if (stringEdited.contains("{[")) {
                    val re = "\\{\\[.*?]}".toRegex()
                    stringEdited = re.replace(stringEdited,"")
                }

                gamePlayMutableList.add(string)
            }

            // Header Information
            for (i in 0 until headerLength.size) {
                raf.seek(mutableListEvent[i])
                charPosition = raf.filePointer
                while (charPosition < mutableListMoves[i]) {
                    val str = raf.readLine()
                    if (str.contains("[Site \"") || str.contains("[Date \"") || str.contains("[Round \"") || str.contains("[White \"") || str.contains(
                            "[Black \""
                        ) || str.contains("[Result \"") || str.contains("[EventDate \"") || str.contains("[PlyCount \"")
                    ) {
                        if (str.contains("[Site \"")) {
                            siteMutableList += str.replace("[Site \"", "").replace("\"]", "")
                        }
                        if (str.contains("[Date \"")) {
                            dateMutableList += str.replace("[Date \"", "").replace("\"]", "")
                        }
                        if (str.contains("[Round \"")) {
                            roundMutableList += str.replace("[Round \"", "").replace("\"]", "")
                        }
                        if (str.contains("[White \"")) {
                            whiteMutableList += str.replace("[White \"", "").replace("\"]", "")
                        }
                        if (str.contains("[Black \"")) {
                            blackMutableList += str.replace("[Black \"", "").replace("\"]", "")
                        }
                        if (str.contains("[Result \"")) {
                            resultMutableList += str.replace("[Result \"", "").replace("\"]", "")
                        }
                        if (str.contains("[EventDate \"")) {
                            eventDateMutableList += str
                        }
                        if (str.contains("[PlyCount \"")) {
                            plyCountMutableList += str
                        }
                    }
                    charPosition = raf.filePointer
                }
            }

        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}

Once I have the pointers, I then load the information in a recycler view so as you're able to select which game (with information visible) you wish.

I have crawled stack overflow regarding this, however the majority of questions are just to read a whole text file and return that, not put pointers into places for reference

Tikhedewal
  • 23
  • 7

1 Answers1

0

So I managed to figure out the 'issues' regarding this. raf.readLine() is EXTREMELY slow. This is a known problem, but not really talked about so much. Anyway I now use .readFully(), which is substantially faster.

Tikhedewal
  • 23
  • 7
  • What do you mean a "known problem"? Is this documented somewhere? Please provide a link. – Code-Apprentice Jun 03 '22 at 07:34
  • I believe the link between `RandomAccessFile` and `readLine()` is the reason for `readLine()` being slow. This is an interesting comparison showing the slow time of `raf`: [Link here](https://stackoverflow.com/a/53144701/15197405) – Tikhedewal Jun 04 '22 at 08:36
  • Since you don't seem to be doing actual random access here, I suggest using `FileReader` and `BufferedReader` instead of `RandomAccessFile`. `RandomAccessFile` is intended to read a file like it is an array. You just jump directly to the part of the file that contains the object you want to read. When used correctly, each object in the file has the same number of bytes which makes it easy to calculate the beginning position of each object. – Code-Apprentice Jun 06 '22 at 14:59