It's tough to recommend exactly which method you should use because your "do something" pseudocode is too vague.
There are two main ways one iterates over a list of something in a functional language like Erlang: map
and fold
.
The big question comes down to this: What do you want to do with the files? Do you want to total something up for the files (ie, total file size or something), or do you want to store some value for each file (ie each file size individually) or do you want to do something to the files and you don't care what the return values for those files are (ie renaming each file)?
I'll give an example of each quickly here using a list of files returned from file:list_dir/1
:
{ok, Filenames} = file:list_dir("some_directory"),
Folding
Here we'll total the filesizes of all files in the directory using lists:foldl
(as @legoscia mentioned, in this case, filelib:fold_files
is probably the better choice)
TotalSize = lists:foldl(fun(Filename,SizeAcc) ->
FileInfo = file:read_file_info("some_directory/" ++ Filename),
FileSize = FileInfo#file_info.size,
SizeAcc + FileSize
end, 0, Filenames).
Mapping
Here, we'll get a list of filenames along with the filesize for each individual file using lists:map
. The resultant list will be of the format = [{"somefile.txt",452}, {"anotherfile.exe",564},...]
:
FileSizes = lists:map(fun(Filename) ->
FileInfo = file:read_file_info("some_directory/" ++ Filename),
FileSize = FileInfo#file_info.size,
{Filename,FileSize}
end,Filenames).
Foreach (a variant of mapping)
The alternative of just renaming files but not caring about recording any data about the files is to demonstrate the use of lists:foreach
, which is generally used exclusively for side-effect programming in which you don't care about the return values, and it works like lists:map
, but doesn't return anything useful (it just returns the atom ok
):
In this case, I'll show renaming each file by adding a ".old" extension to each filename:
lists:foreach(fun(Filename) ->
OldFile = "some_directory/" ++ Filename,
NewFile = OldFile ++ ".old",
file:rename(OldFile, NewFile),
end,Filenames).
Recursion
Of course, the raw version of all of these - if map
, fold
, foreach
, or list comprehensions (which I didn't cover, but are basically another variant of map
with a filter
component) are too restricting for whatever reason - you can do things recursively:
do_something_with_files([]) -> ok;
do_something_with_files([CurrentFile|RestOfFiles]) ->
do_something(CurrentFile),
do_something_with_files(RestOfFiles).
There are a lot of ways to do what you need with Erlang, but unlike with procedural languages like VB, you must think a little ahead to what you want to track or do in order to determine how you wish to iterate over your lists, since you're limited by immutable variables in Erlang.
Note: In order to use the #file_info
record, you'll need to include the file.hrl file at the top of your module with:
-include_lib("kernel/include/file.hrl").