Garbage in file name. File::getName

I’m trying to convert the name of a file object to a string, so I can display it on an lcd screen, and so I can do some validation on it to make sure its the kind of file I’m looking for. I’m using the getName() method which returns an array of characters that has to be iterated over.

However, when I print the the serial monitor, I get the file name and then a bunch of garbage at the end of the name. The name of the file is “0 - test.mid”, and I get “0 - test.midmt.mid⸮⸮⸮⸮0 - tetest.mid- test.mid⸮⸮*⸮. nk: 1 . ack: e⸮⸮⸮⸮w⸮⸮⸮⸮⸮⸮v⸮” printed to the Serial monitor.

Here’s the relevant method:

String fileNameAsString(File activeFile) {
  char filename[100];
  String fn = "";

  activeFile.getName(filename, 100);

  for (int i = 0; i < 100; i++)
  {
    char character = filename[i];
    fn = fn + filename[i];
  }
  Serial.print(fn);
  Serial.println();
  Serial.print("done");
  return fn;
}

I’m trying to convert the name of a file object to a string

Looks to me like you are trying to convert it to a String, wasting resources.

  char filename[100];

To hold 8.3 file names?

  activeFile.getName(filename, 100);

  for (int i = 0; i < 100; i++)
  {
    char character = filename[i];

You seem to assume that the name will always be exactly 100 characters long. Hardly a valid assumption, in my universe.

You could try using a reasonable sized array, and stop copy data to the resource wasting String when you encounter the NULL.

  activeFile.getName(filename, 100);

What does the second parameter relate to ?

Which SD library are you using ?

PaulS:
Looks to me like you are trying to convert it to a String, wasting resources.

Thats correct, is there a better way to do it? I need to send it the lcd screen which takes a string, and I need to determine from the name the file extension. I guess the latter could be determined by iterating over the array and not building a string, but I'm not sure how else to deliver something to the lcd screen.

  char filename[100];

To hold 8.3 file names?

I'm confused. I thought the character array is whats sent to the getName function to ultimately contain the characters of the filename. What do you mean when you say 8.3 file names?

You seem to assume that the name will always be exactly 100 characters long. Hardly a valid assumption, in my universe.

You could try using a reasonable sized array, and stop copy data to the resource wasting String when you encounter the NULL.

In a strongly typed language I have to define the length of the array no? 100 is a catch all. It fails in the same manner when I use an array size of 25- just less characters. It didn't seem to like my null checked, it returned "NULL used in arithmetic", which is odd because it should be evaluating as a character. Do you think the nulls are causing the garbage? It just seems so random, I would expect nothing to be returned before a bunch of random characters.

UKHeliBob:

  activeFile.getName(filename, 100);

What does the second parameter relate to ?

Which SD library are you using ?

I believe that is the byte size. I'm using SdFat, but I read somewhere I should use the default File class because there's an issue with getName in the current version of the SdFat lib. getName doesn't appear to work in the latest version.

What do you mean when you say 8.3 file names?

The youth of today knows nothing it seems !

Back in the Dark Ages of computing file names were limited to 8 characters plus a 3 character extension usually used to denote the type of file. The SD libraries that I have come across honour this restriction hence the incredulity at you allowing for 100 characters in the file name.

UKHeliBob:
The youth of today knows nothing it seems !

Back in the Dark Ages of computing file names were limited to 8 characters plus a 3 character extension usually used to denote the type of file. The SD libraries that I have come across honour this restriction hence the incredulity at you allowing for 100 characters in the file name.

Ah got it, good to know. I gave it a shot on the File::getName. The method itself didn't complain, I tried 2.3 as the size. I shortened my filename array to 20. I was expecting "0 .mid" (2 + 3 character extension) to be returned, but instead I got a string of " ack:⸮", in otherwords now its giving me a total garbage string.

is there a better way to do it?

Of course. Make the array global, not local to the function. Then, you don't need to pass it around.

What do you mean when you say 8.3 file names?

The SD library is constrained to using names that have no more than 8 characters before the dot and no more than 3 characters after the dot.

The name of the file does NOT contain any information about the path to the file.

In a strongly typed language I have to define the length of the array no?

Strongly typed has little to do with anything. The Arduino is programmed in C++, which happens to be a strongly typed language. Yes, you have to define the size of the array. But, you wouldn't use a box big enough to hold a car to send your Mom a thimble, would you?

It didn't seem to like my null checked, it returned "NULL used in arithmetic", which is odd because it should be evaluating as a character.

Then, you wrote the code incorrectly.

The array that is filled is NULL terminated.

byte nameLength = strlen(filename);

Then, iterate nameLength times copying data, if you just MUST use a String.

PaulS:
The array that is filled is NULL terminated.

byte nameLength = strlen(filename);

I wasn't aware that it was null terminated. This was the solution. I'm able to iterate over everything thats not null, and now the names look correct. Thanks.

If anyone else ever runs into this issue, here’s the solution I came up with. The key was to use the length of the array because its null limited:

String fileNameAsString(File activeFile) {
  char filename[20];
  String fn = "";

  activeFile.getName(filename, 50);

  for (int i = 0; i < strlen(filename); i++)
  {
    fn = fn + filename[i];
  }

  return fn;
}

Sorry, but I don't understand the need to use a String

After doing

  activeFile.getName(filename, 50);

the filename variable contains the file name a a null terminated string. Why the need to copy it to a String ?

UKHeliBob:
Sorry, but I don't understand the need to use a String

After doing

  activeFile.getName(filename, 50);

the filename variable contains the file name a a null terminated string. Why the need to copy it to a String ?

I could very well be missing something, but want you send to the getName function that the name gets assigned to is an array of chars, not a string.

I assume that you mean

want what you send to the getName function that the name gets assigned to is an array of chars, not a string.

Yes, the name of the file appears to be assigned to an array of chars. From your subsequent code it appears that this array is terminated by a zero, thus making it a C style string (lowercase s). If that were not the case then strlen() would not return the correct length.

Why, having got the file name as a string, do you convert it to s String (uppercase S) ?

UKHeliBob:
Why, having got the file name as a string, do you convert it to s String (uppercase S) ?

Well I'll be. Yes I just tested it and it works.

I guess I'm not understanding how the typing is working in this scenario. Its an array of characters. But its also a string? It definitely doesn't complain when I return the character array in the String function. And the lcd library accepts the returned value as a string and displays it.

Its an array of characters. But its also a string?

A string (lowercase s) is nothing but an array of chars terminated with a zero

Please be very careful when you refer to strings or Strings that you use the correct capitalisation as they do not refer to the same thing at all and different functions are used to manipulate the two types

the lcd library accepts the returned value as a string and displays it.

No surprise there