Problem with love.filesystem.getInfo returning nil.

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
captainPicard99
Prole
Posts: 4
Joined: Fri Jul 30, 2021 8:44 pm

Problem with love.filesystem.getInfo returning nil.

Post by captainPicard99 »

I'm trying to load a list of files (in this case songs) in a directory, and discard anything that is a directory
the only problem is that getInfo(file) keeps returning nil, implying that said file doesn't exist
BUT, if I remove that if statement there, then files turns up perfectly fine. if the files didn't exist, then you'd think that that wouldn't happen
so I'm sure the files exist, but getInfo can't seem to figure it out.

Here is the code -

Code: Select all

songLoader.loadSongs = function(dir)
    local isDirs = {}
    local lfs = love.filesystem
    local files = love.filesystem.getDirectoryItems(dir)
    for k, file in ipairs(files) do
        local info = love.filesystem.getInfo(file)
	    if info.type == 'directory' then
            isDirs[k] = file
            files[k] = nil
        end
    end

    return files
end 
BTW, the reason I am using = nil instead of table.remove is because table.remove screws up the iteration index and causes problems when iterating like this.

The array returned is then looped through and printed in another LUA file like this:

Code: Select all

local fileList = ""
    for k, file in ipairs(songLoader.loadSongs("Music")) do
        fileList = fileList .. k .. ". " .. file
    end
Here is the error message:
Image
here is the directory -
Image
Here is the output with the filtering lines commented out:
1. Random Chance - The Useless Album 2. appear.txt 3. tester
Here is the output I want:
1. appear.txt

WHY OH WHY does getInfo keep returning nil even though I (and the code, since it can clearly print them with the filter removed) KNOW the files exist?
User avatar
GVovkiv
Party member
Posts: 668
Joined: Fri Jan 15, 2021 7:29 am

Re: Problem with love.filesystem.getInfo returning nil.

Post by GVovkiv »

Problem 1:

Code: Select all

local loadSongs = function()
    local files = love.filesystem.getDirectoryItems("")
    local onlyFiles = {}
    for k, file in ipairs(files) do
        if love.filesystem.getInfo(file).type == "file" then
          table.insert(onlyFiles, file)
        end
    end
    return onlyFiles
end

for i, v in ipairs(loadSongs()) do
  print(v)
end
(It will print only FILES from SOURCE and IDENTITY (Which locates in APPDATA) directories)

Reason, why i remove dir argument:
Because love.filesystem can't get data outside of appdata and source/.love archive
If you need get data outside that 2 directories, then you may find useful megagrump's https://github.com/megagrump/nativefs
which allow get files and stuff outside love's filesystem sandbox, replace all love's filesystem function with nativefs's and update your code with my example
or if you don't and wants only get data inside appdata/source, then just update your function with my example
MrFariator
Party member
Posts: 509
Joined: Wed Oct 05, 2016 11:53 am

Re: Problem with love.filesystem.getInfo returning nil.

Post by MrFariator »

GVovkiv is correct in that you can only load files from your project's "folder" or archive (where main.lua is), and save folder (appdata on windows, etc), but it does not answer the problem here. Lets take a deeper look.

If you take a look at the wiki page for love.filesystem.getInfo, it states the following:
Returns
table info (nil)
A table containing information about the specified path, or nil if nothing exists at the path.
Given your error message, the directory you're giving to the function is making it a return a nil, and indexing a nil like it's a table is always going to cause a crash. As such, you want to add a guard in your loop:

Code: Select all

for k, file in ipairs(files) do
  local info = love.filesystem.getInfo(file)
  if info and info.type == 'directory' then -- notice how this line changed; now info.type is checked only if "info" is a non-falsy value
    isDirs[k] = file
    files[k] = nil
  end
end
Now, you may ask - why is getInfo returning nil values in the first place, suggesting that the elements in that path don't exist? Well, if you look at love.filesystem.getDirectoryItems on the wiki, you'll notice that the function returns a table of files and subdirectiories in the given path, it does not give you a path to those files.

As such, you'lll have to do something like:

Code: Select all

for k, file in ipairs(files) do
  local info = love.filesystem.getInfo(dir .. "/" .. file) -- prefix the directory, so that we pass the path properly
  if info and info.type == 'directory' then
    isDirs[k] = file
    files[k] = nil
  end
end
BTW, the reason I am using = nil instead of table.remove is because table.remove screws up the iteration index and causes problems when iterating like this.
Actually, because you're using ipairs, things will still get screwed up this way as well.

Code: Select all

local test = {1,2,4,5,6,7,9,8,9,10}
test[6] = nil

for k,v in ipairs(test) do
  print(k,v)
end
--output:
1 1
2 2
3 4
4 5
5 6
As you see, because I created that gap at index 6 by assigning nil to it, the ipairs loop stops at the first gap (so everything past index six gets ignored). If you want to remove elements from a table as you're iterating through it, you generally use table.remove and iterate in reverse.

Code: Select all

local test = {1,2,3,4,5,6,7,8,9,10}

-- remove element divisible by two
for i = #test, 1, -1 do
  if test[i] % 2 == 0 then
    table.remove(test, i)
  end
end

for k,v in ipairs(test) do
  print(k,v)
end

--output:
1 1
2 3
3 5
4 7
5 9
Alternatively, use a while loop and increase the index only when table.remove is not called. In your case though, you can also use pairs in place of ipairs, if you want to use your code as-is. The pairs iterator will not care about gaps in any shape or form, at the cost of worse performance (neglible for one-time or infrequent operations) and unpredictable processing order.
captainPicard99
Prole
Posts: 4
Joined: Fri Jul 30, 2021 8:44 pm

Re: Problem with love.filesystem.getInfo returning nil.

Post by captainPicard99 »

MrFariator wrote: Sat Jul 31, 2021 9:04 am Well, if you look at love.filesystem.getDirectoryItems on the wiki, you'll notice that the function returns a table of files and subdirectiories in the given path, it does not give you a path to those files.
Thank you SO MUCH. I feel so stupid for not thinking of that earlier! I don't need to get any directorties outside of the game.love directory, because this is for allowing players to add their own music as well as choosing from built-in tracks for the in-game radio feature. Thanks SO SO much for this!
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 14 guests