This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Goof's profile picture

[Solved] - listing all files on the computer ( fs.list() )

Started by Goof, 21 May 2014 - 01:57 PM
Goof #1
Posted 21 May 2014 - 03:57 PM
Hello

EDIT: Added current code

I've got into a bit of a weird problem, how to get all files + paths of every single file ( not readonly ) on the computer…
But i've forgot how to do it…

My only and current code i've been able set up is:
Spoiler

local response = {}
	local currentPath = "/"
	local list = fs.list( currentPath )
	while true do
	  if #list == 0 then
		break
	  end
	  for _, path in ipairs( list ) do
		if not fs.isReadOnly( path ) then
		  print( path )
		  if fs.isDir( path ) then
			currentPath = currentPath .. path
			list = fs.list( currentPath )
		  else
			Util.PutIntoTable( response, currentPath .. path )
		  end
		end
	  end
	  sleep(5)
	end
  return response

Anybody able to help?


Thanks in advance
Edited on 19 October 2014 - 01:57 PM
Lyqyd #2
Posted 21 May 2014 - 03:58 PM
The easiest way would be to simply build a table with a recursive function that uses fs.list.
Goof #3
Posted 21 May 2014 - 04:01 PM
Edited OP with current code.

Hmm… Yeah. thats what im trying… but i dont know exactly how to get it work properly..
(it just goes into one of the folders and keep displaying the same files in that folder)
Edited on 21 May 2014 - 03:03 PM
Agoldfish #4
Posted 21 May 2014 - 04:37 PM
I think good ol'

fs.list("/")
Should work…
Goof #5
Posted 21 May 2014 - 05:02 PM
I think good ol'

fs.list("/")
Should work…

Did you read my code?
..

The problem im having is:
(it just goes into one of the folders and keep displaying the same files in that folder and being stuck in that loop)
apemanzilla #6
Posted 21 May 2014 - 05:07 PM

function listAll(path)
  local path = path or ""
  local tbl = fs.list(path)
  for k,v in pairs(path) do
    if fs.isDir(v) then
      local result = listAll(fs.combine(path,v))
      for k,v in pairs(result) do
        table.insert(tbl,fs.combine(path,v))
      end
    end  
  end
  return tbl  
end
Run that code with no arguments to get a list of all files on the computer.
Edited on 21 May 2014 - 03:08 PM
Goof #7
Posted 21 May 2014 - 05:15 PM
hmm

That doesnt return the full path of the file…
And sholdnt the loop go through "tbl" instead of "path" ?
Agoldfish #8
Posted 21 May 2014 - 06:08 PM
If I understand correctly, you want to list every editable file? If so:

for _, f in pairs(fs.list("/")) do
    if not fs.isReadOnly(f) then
	  --#blah
    end
  end
Should work.
Lyqyd #9
Posted 21 May 2014 - 06:09 PM
His code is a little wonky, try this instead. Again, call it with no arguments.


local function listAll(_path, _files)
  local path = _path or ""
  local files = _files or {}
  if #path > 1 then table.insert(files, path) end
  for _, file in ipairs(fs.list(path)) do
    local path = fs.combine(path, file)
    if fs.isDir(path) then
      listAll(path, files)
    else
      table.insert(files, path)
    end
  end
  return files
end

You can also throw a readOnly check in there if you like.
CometWolf #10
Posted 21 May 2014 - 06:18 PM
If I understand correctly, you want to list every editable file? If so:

for _, f in pairs(fs.list("/")) do
	if not fs.isReadOnly(f) then
	  --#blah
	end
  end
Should work.
As others have said, this simply won't be enough. You need the recursive function, otherwise you'll only get the contents of the root("/") folder.
Edited on 21 May 2014 - 04:18 PM
apemanzilla #11
Posted 21 May 2014 - 07:07 PM
His code is a little wonky, try this instead. Again, call it with no arguments.


local function listAll(_path, _files)
  local path = _path or ""
  local files = _files or {}
  if #path > 1 then table.insert(files, path) end
  for _, file in ipairs(fs.list(path)) do
    local path = fs.combine(path, file)
    if fs.isDir(path) then
      listAll(path, files)
    else
      table.insert(files, path)
    end
  end
  return files
end

You can also throw a readOnly check in there if you like.
I guess this is what I get for trying to whip up a function on my iPad three minutes before lunch :P/>
Goof #12
Posted 21 May 2014 - 09:24 PM
Hmm… Yeah.. Lyqyd's example is the most effiecent and compact way i can see it…

Thank you for helping me out, everyone.

:D/>
theoriginalbit #13
Posted 22 May 2014 - 02:02 AM
one problem you can have with this however is with large filesystems it is possible to have ComputerCraft terminate your script due to failure to yield, as such you can make a solution that uses coroutines so this doesn't happen. Now one thing with this solution is it doesn't make a table of values automatically for you, instead you have to use it in a for loop

Code

local function fsList(start)
  local function yieldFsList(startPath)
	local list = fs.list(startPath)
	for _, file in ipairs(list) do
	  local path = fs.combine(startPath, file)
	  if fs.isDir(path) then
		yieldFsList(path)
	  else
		coroutine.yield(path, file)
	  end
	end
  end

  return coroutine.wrap(function() yieldFsList(start or "/") end)
end

Commented Code

--# we use this function just like we use `pairs` or `ipairs`
--# supply it with a starting path to iterate, however if you
--# don't supply a path it will assume root '/'
local function fsList(start)
  --# this is the recursive function
  local function yieldFsList(startPath)
	--# get a list of all the files and folders in the current directory
	local list = fs.list(startPath)
	--# iterate the list
	for _, file in ipairs(list) do
	  --# resolve its path
	  local path = fs.combine(startPath, file)
	  --# if its a directory run this function on it
	  if fs.isDir(path) then
		yieldFsList(path)
	  --# otherwise return the fullpath to the file and the filename
	  else
		coroutine.yield(path, file)
	  end
	end
  end

  return coroutine.wrap(function() yieldFsList(start or "/") end)
end

Usage ExamplesListing programs

for fullpath, filename in fsList('/rom/programs') do
  print(filename, ' : ', fullpath)
end

Listing all files

for fullpath, filename in fsList() do
  print(filename, ' : ', fullpath)
end

Saving a list to a table

local files = {}
for fullpath, filename in fsList() do
  table.insert(files, fullpath)
end

Searching for a particular file

for fullpath, filename in fsList("rom/programs") do
  if filename == "paint" then
	print("Found it! It was in: "..fullpath)
  end
end
the above code is looking for the paint program, in ComputerCraft versions below 1.6 it will find it in rom/programs/color/paint however in versions above ComputerCraft 1.6 it will find it in rom/programs/fun/advanced/paint I hope by providing this example it shows how powerful this method can be. Before you say 'but CC 1.6 has fs.find this is useless' it is definitely not, fs.find will return the first matching instance, this will not.

Alternatively you can also adapt either Lyqyd's or my functions to be able to ignore certain paths too. Here's an example with mine
Code


local function fsList(start, ignores)
  if type(start) == "table" then
    ignores, start = start, "/"
  end
  local function yieldFsList(startPath, ignorePaths)
    local list = fs.list(startPath)
    for _, file in ipairs(list) do
      local path = fs.combine(startPath, file)
      for _,v in ipairs(ignorePaths) do
        if path == v then
          return
        end
      end
      if fs.isDir(path) then
        yieldFsList(path, ignorePaths)
      else
        coroutine.yield(path, file)
      end
    end
  end

  return coroutine.wrap(function() yieldFsList(start or "/", ignores or {}) end)
end

Usage ExampleSearching for `paint` but not in rom

for fullpath, filename in fsList({"rom"}) do
  if filename == "paint" then
    print("Found it! It was in: "..fullpath)
  end
end
NOTE: it shouldn't find one, unless you have a file called `paint` :P/>
Edited on 22 May 2014 - 12:20 AM
Lyqyd #14
Posted 22 May 2014 - 07:04 AM
Wait, have you actually had a large enough quantity of files on a single ComputerCraft computer that this would take longer than ten seconds to complete? That's impressive, albeit in a kind of horrifying way.
theoriginalbit #15
Posted 22 May 2014 - 07:38 AM
Wait, have you actually had a large enough quantity of files on a single ComputerCraft computer that this would take longer than ten seconds to complete? That's impressive, albeit in a kind of horrifying way.
haha yeah I have actually. I had a few different big 'OSes' on a computer and yeah CC killed the program 'cause the list was taking too long. haha. Also the 10 seconds kill time is a bit, well, a bit variable, on a server once I actually had a script killed after ~5 seconds.
Goof #16
Posted 22 May 2014 - 03:08 PM
Well… This doesnt actually matter of the time…
As you said, i could call the yields…
But the only thing im going to use this for, is to return a table with full paths, then upload everything to a website xD…

(its a "quick-function" to upload my whole computer to a certain web… )

I think im going to look into TOBIT's examples, and modify it a bit.

Thank you guys!


EDIT:



Btw. When we talk about website, i actually have an "semi" weird question about PHP
( Yes, i think this topic can go into General now, when we're talking bout' other programming languages. )

I've made a website, with an upload file ( upload.php )

This upload.php page accepts an Auth key ( to ensure its me using the web )
Then it uses a Method ( "startSession", "inSession", "endSession" )
then it uses fileData, and fileName…

But my problem is to create a new folder corresponding to latest folder ID, where the session is going to be in.

( For example: )

 uploads/1/testFile.lua
If that "1" folder already exists when a new session is started, its going to create the folder with the name of
"2"
Like this:

 uploads/2/EMPTYFOLDER


Then when posting "inSession" its going to create single files and folders with the supplied fileData inside.
For example, lets say im uploading a file in a System/test.lua folder, to the web

Then the following is going to happen in the uploads/2 folder

       Folders are created here to ensure the best compatibility of getting everything again.
uploads/2/System/test.lua



Then whenever i end the session, its going to close all connections and stop writing files to that folder.


Btw… You can ask for more info, but since i dont know that much php, im a bit noobish


Thanks in Advance
Edited on 22 May 2014 - 01:16 PM
Gumball #17
Posted 18 September 2014 - 12:46 AM
If you just want to list it, do this:

files = fs.list()
print(files)
repeat
until not line
print("Finished printing lines")
Dog #18
Posted 18 September 2014 - 12:55 AM
So, your code will create a table of the file names in the root (ignoring all the files in sub directories), fail to print that list to screen since it's a table (and probably error out). If it doesn't error out, then it'll print "Finished printing lines" because the unnecessary repeat loop will immediately terminate since 'line' is never declared or assigned a value.

Sorry to sound so harsh, but not only does your code not work, it doesn't even address the OP's request.

For reference, your code (to list the files in the root) should be…

local files = fs.list()
for i = 1, #files do
  print(files[i])
end
print("Finished printing lines")
Edited on 17 September 2014 - 11:22 PM
Gumball #19
Posted 19 October 2014 - 01:29 AM
Wasn't that good at coding then, heres my code that even colors the files and directories, ROM is green:


local tArgs = {...}
if(#tArgs ~=1) then
  files = fs.list("/")
elseif(#tArgs == 1) then
  for file=1,#tArgs do
    files = fs.list(files[file])
    if(fs.isDir(files[file]) then
	  if(files[file] == "rom") then
	    term.setTextColor(colors.green)
	    print(files[file])
	  else
	 
	  term.setTextColor(colors.yellow)
	  print(files[file])
    end
   
    else
    term.setTextColor(colors.blue)
    print(files[file])
end
  
 

 

Thats the simplest I could think of. xD
Goof #20
Posted 19 October 2014 - 03:55 PM
Hmm.. Didnt i tell you this was solved?

I must've forgotten that.

Well.. thanks for the answers, this is now solved :P/>