I'm having a problem with the parsecsv that I can't figure out.
Basically, in order to generate map tiles, I am opening five .csv files, and reading from them. The map tiles are generated in pairs of twos. I can generate 25 pairs without any trouble, but the program always crashes when the 26th pair is generated, after the set of five .csv files are opened for the 51st time. This is the error thrown:
main.nim(38) main
main.nim(32) main
mainScreen.nim(627) mainScreen
mainScreen.nim(415) processInput
endTurnFunctions.nim(33) endTurn
tileGenerator.nim(1141) createMapTiles
tileGenerator.nim(34) generateTile
miscFunctions.nim(27) readCSV
parsecsv.nim(110) open
parsecsv.nim(79) error
parsecsv.nim(75) raiseEInvalidCsv
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Line 27 of miscFunctions refers to line 7 of readCSV():
p.open(fileName)
I believe the means that the .csv file can't be found, but it is found without problem the first 50 times, and no exception is raised when
try:
discard open(fileName)
except:
raise newException(IOError, (fileName & " not found"))
is run. This, and the fact that it always happens after the same number of files are opened, makes me think it is some sort of memory error, but I am closing the file every time, so I am not sure why that would be. The full proc is given below. If anyone has any idea of what the problem could be, I would greatly appreciate the insight.
proc readCSV*(fileName: string, minRow: int, numRows: int = 1): auto =
var p: CsvParser
try:
discard open(fileName)
except:
raise newException(IOError, (fileName & " not found"))
echo fileName
p.open(fileName)
let rowsToRead = numRows - minRow
var tableEntries = newSeq[CSVRow](numRows) # will be appended as tableEntries[y][x]
var convertedTable: seq[seq[string]] = @[]
for i in 0 .. (minRow + numRows - 1):
try:
discard p.readRow
if i >= minRow:
tableEntries[i - minRow] = p.row # i - minRow to begin indexing at 0
except:
raise newException(IOError, "row not found")
# need to convert from tableEntries[y][x] to tableEntries[x][y]
for x in 0..<tableEntries[0].len:
convertedTable &= newSeq[string](tableEntries.len)
for y in 0..<rowsToRead:
for x in 0..<tableEntries[0].len:
convertedTable[x][y] = tableEntries[y][x]
p.close()
result = convertedTable
return result
You are forgetting to pass p CsvParser arg
var p: CsvParser
try:
#discard open(fileName) # missing arg
p.open(fileName) # this works
except:
raise newException(IOError, (fileName & " not found"))
Well, I had the impression that he does a system.open() call first -- to check if file exist, followed by p.open()...
And for system.open() there is no corresponding close, so maybe OS refuses opening the the file again?
Yeah, that is it. I was pretty sure it was a problem closing the file, but thought that the file didn't remain open since I didn't assign it to a variable, which is quite foolish actually - thanks Stefan!
However, if I do as Parashurama suggested:
try:
p.open(fileName)
except:
raise newException(IOError, (fileName & " not found"))
I get the generic parsecsv error instead of my custom exception, if the file isn't found. This isn't too bad, since I can find the errant name based on the line numbers in the stack trace, but it would be nice to keep the exception I have. Is there a way to close the system.open(), or maybe to test for the file without using open()?
With existsFile you could do something like
import os
let filename = "my.png"
if not existsFile(filename):
raise newException(IOError, (filename & " not found"))