Choose a random file in a folder

Hi ! For an audio project, I'm trying to choose a random file in a folder (files with random names).

The only solution I found at this time is to:

  • list all files and count them
  • choose a random value between 1 and the total of files
  • re-list all files and stop when a counter of files (incremented at each file) matches the random value

It can be very slow on big folders, so I'm wondering if there are better solutions.

Thanks

Sure! Keep a file of names as you add them to folders.

You mean "appending their names in a text file in the SD card, count the lines, and pick a random name in the list" ?

That should work, don't you think?

Use only numbers for file names, that is to say:

001.wav
002.wav
003.wav
.
.
.
999.wav

@Paul_KD7HB Yes, good idea, I will try ! Thanks !

@xfpd Yes, it is the solution I actually use, but it limits the ability to use random name files

How does it limit randomness?

play(random(999).wav);

@xfpd I mean, you need to follow the naming guideline, you can't add "whatever.wav" :slight_smile:
But it works

If you want to randomly select an element from a list of unknown size, you could try the following strategy:

  • Select the first element in the list as a candidate with probability 1.
  • Select the second element in the list as a candidate with probability 1/2.
  • Select the third element in the list as a candidate with probability 1/3.
  • etc.

In the following example, we assume we receive a zero terminated array:

char const* pick(char const* const files[]) {
  char const* candidate {nullptr};
  for (size_t i {0}; files[i]; ++i) {
    if (not random(i + 1)) {
      candidate = files[i];
    }
  }
  return candidate;
}

Usage:

char const* files[] {"a", "b", "c", "d", "e", nullptr};
Serial.println(pick(files));

Instead of an array, you can use a function that returns the next entry in a directory list. The following example is based on the list files example (untested):

void pick(char name[], File dir) {
  File entry {dir.openNextFile()};
  for (size_t i {0}; entry; ++i) {
    if (not random(i + 1)) {
      strcpy(name, entry.name());
    }
    entry.close();
    entry = dir.openNextFile();
  }
}

Usage:

void setup() {
  Serial.begin(9600);

  char name[20] {};

  File root {SD.open("/")};
  pick(name, root);
  root.close();

  Serial.println(name);
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.