проблема с открытием файлы с sd card

sauges
Offline
Зарегистрирован: 16.05.2015

всем привет

подскажите пожалуйста

#include <SD.h>

File myFile;

String name[2]={"test.txt","test2.txt"};

void setup()
{
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
   pinMode(10, OUTPUT);
  SD.begin(10))

  myFile = SD.open(name[1]);
  if (myFile) {
    Serial.println("test.txt:");
    while (myFile.available()) {
    	Serial.write(myFile.read());
    }
    
    myFile.close();
  } 
}

void loop()
{

}

как открыть файл с помощью массива String

Компилятор пишет:


ReadWrite:5: error: cannot convert 'const char*' to 'String*' in initialization
ReadWrite:5: error: cannot convert 'const char*' to 'String*' in initialization
ReadWrite.ino: In function 'void setup()':
ReadWrite:22: error: no matching function for call to 'SDClass::open(String*&)'
D:\Program Files\Arduino\libraries\SD/SD.h:74: note: candidates are: File SDClass::open(const char*, uint8_t)

можно ли что нибудь сделать?

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Имена файлов объявите, как "char*".

Yarik.Yar
Offline
Зарегистрирован: 07.09.2014

И не забудьте, что счёт в массиве начинается с нуля...

maksim
Offline
Зарегистрирован: 12.02.2012
  char buf[10];
  name[0].toCharArray(buf, name[0].length());
  myFile = SD.open(buf);

 

sauges
Offline
Зарегистрирован: 16.05.2015

спасибо maksim

я сделал как вы написали

но почему то

в имени теряется последняя буква

выдает не "test.txt" а "test.tx"

maksim
Offline
Зарегистрирован: 12.02.2012
char buf[13];
name[0].toCharArray(buf, name[0].length()+1);
myFile = SD.open(buf);

 

sauges
Offline
Зарегистрирован: 16.05.2015

спасибо 

 

bassizlink
Offline
Зарегистрирован: 06.02.2022
#include <SPI.h>
#include <SD.h>

File root;
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  root = SD.open("/");
  uint32_t index = 1;
  while (true) {
    root.seek(32*index);
    File entry = root.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    Serial.print(entry.name());
    Serial.println("="+String(index));
    index++;
    delay(20);
  }
}
void loop() {
  // nothing happens after setup finishes.
}

 

bassizlink
Offline
Зарегистрирован: 06.02.2022

Добрый день.Написал небольшой тестовый код.Не могу понять в чем ошибка.Попытался вывести список файлов и каталогов по индексу.

bassizlink
Offline
Зарегистрирован: 06.02.2022
Initializing SD card...
initialization done.
SYSTEM~1=1
SYSTEM~1=2
TEST6.TXT=3
TEST1.TXT=4
TEST1.TXT=5
TEST1.TXT=6
TEST1.TXT=7
TEST1.TXT=8
TEST1.TXT=9
TEST1.TXT=10
TEST1.TXT=11
TEST1.TXT=12
TEST1.TXT=13
TEST1.TXT=14
TEST1.TXT=15
TEST1.TXT=16
TEST1.TXT=17
TEST1.TXT=18
TEST1.TXT=19
TEST1.TXT=20
TEST1.TXT=21
TEST1.TXT=22
TEST1.TXT=23
TEST1.TXT=24
TEST1.TXT=25
Initializing SD card...
initialization done.
TEST1.TXT=26
TEST1.TXT=27
TEST1.TXT=28
TEST2.TXT=29
TEST3.TXT=30
TEST8.TXT=31
TEST5.TXT=32
TEST7~1.TXT=33
TEST7~1.TXT=34
TEST7~1.TXT=35
TEST4~1.TXT=36
TEST4~1.TXT=37
TEST0.TXT=38
TEST0.TXT=39
TEST0.TXT=40
PAPKA0=41
PAPKA0=42
PAPKA0=43
PAPKA1=44
PAPKA1=45
PAPKA1=46
PAPKA5=47
PAPKA5=48
PAPKA5=49
PAPKA5=50
Initializing SD card...
initialization done.
PAPKA5=50
PAPKA5=51
PAPKA5=52
JHGJHJH5.TXT=53
JHGJHJH5.TXT=54
JHGJHJH5.TXT=55
JHGJHJH5.TXT=56
JHGJHJH5.TXT=57
PAPK7=58
PAPK7=59
PAPK7=60
PAPK7=61
UHKJHLLK=62
UHKJHLLK=63
UHKJHLLK=64
UHKJHLLK=65
UHKJHLLK=66
UHKJHLLK=67
UHKJHLLK=68
WINRAR~1.RAR=69
WINRAR~1.RAR=70
WINRAR~1.RAR=71
WINRAR~1.RAR=72
WINRAR~1.RAR=73
WINRAR~1.RAR=74

 

bassizlink
Offline
Зарегистрирован: 06.02.2022

Выше вывод в Serial.Моя задача найти способ выводить имя файла или каталога по индексу.В библиотеке насколько я понял нет метода openPreviusFile(), есть только openNextFile().Основная проблема в том, что в данном тесте вывод приостанавливается на определенных значениях индекса, но если вручную установить последнее значение, то вывод продолжается .Так же не понятно откуда берутся дубликаты имен.

bassizlink
Offline
Зарегистрирован: 06.02.2022

Добавил entry.close(), в цикл, убрал задержку.Ситуация стала лучше, распечатались все файлы и каталоги корневой директории, что мне на данном этапе нужно, но все же непонятно откуда дубликаты имен?

b707
Offline
Зарегистрирован: 26.05.2017

bassizlink пишет:

Выше вывод в Serial.Моя задача найти способ выводить имя файла или каталога по индексу.

что такое индекс в данном случае?

Имхо, ваша проблема именно в том и состоит, что вы приплели сюда какой-то индекс... который надо убрать из кода.

Метод openNextFile() сам переходит к следующему файлу, операция seek() тут совершенна лишняя и именно она приводит к повторению имен одних и тех же файлов.

bassizlink
Offline
Зарегистрирован: 06.02.2022

Индекс в данном случае имеется ввиду порядковый номер каталога или файла в текущей директории.

bassizlink
Offline
Зарегистрирован: 06.02.2022

Вариант вернуться к началу и пролистать N-1 мне не подходит, так как это очень медленно .Так же не подходит держать массив строк, так как памяти не хватит при большом количестве файлов и каталогов.

bassizlink
Offline
Зарегистрирован: 06.02.2022

b707 пишет:

bassizlink пишет:

Выше вывод в Serial.Моя задача найти способ выводить имя файла или каталога по индексу.

что такое индекс в данном случае?

Имхо, ваша проблема именно в том и состоит, что вы приплели сюда какой-то индекс... который надо убрать из кода.

Метод openNextFile() сам переходит к следующему файлу, операция seek() тут совершенна лишняя и именно она приводит к повторению имен одних и тех же файлов.

Что делает openNextFile(), мне понятно.В конечном итоге мне нужно иметь возможность открывать предыдущий файл.Например, я вывожу на экран текущее имя файла, по нажатию выводится следующий файл, по нажатию другой кнопки, должен открыться предыдущий файл, имя его выводится на экран.

bassizlink
Offline
Зарегистрирован: 06.02.2022

Понимаю,чужие мысли трудно понять и обьяснить.Но все же если не понятно, то попробую довавить.Нажимаешь на кнопку, индекс файла увеличивается i++, выводится соответствущее имя файла, жмешь другую индекс уменьшается i--, выводится имя согласно индексу.Я могу реагировать на повтор имени, но боюсь, что такой подход приведет к медленному интерфейсу пользователя, в случае, если их много.Поэтому хочется разобраться с этим.Полагаю, что повторы, это ранее удаленные файлы.    

bassizlink
Offline
Зарегистрирован: 06.02.2022

Думаю, что когда я пытался копировать файл, система Windows видела, что появился файл с одинаковым именем, создавала новый файл с именем   "ИМЯ+копия файла1","ИМЯ+копия файла2" и т.д., а файл с повторным именем просто пометила как удаленный.Тоесть повторы это удаленные файлы при попытке копирования .В связи с этим возникает вопрос, как различить удаленный файл от не удаленного?

bassizlink
Offline
Зарегистрирован: 06.02.2022

Догадка оказалась верной, если первый байт записи файла в файле директории равен 0xE5 или 0x05, согласно Википедия, то файл или директория являются свободными.

bassizlink
Offline
Зарегистрирован: 06.02.2022

#include <SPI.h>
#include <SD.h>

File root;
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  root = SD.open("/");
  uint32_t index = 0;
  while (true) {
    while (true){
      root.seek(32*index);
      uint8_t n = root.peek();
      if (n!=0xE5 && n!=0x05) {
        // no more files
        break;
      }
      index++;
    }
    File entry = root.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    Serial.print(entry.name());
    Serial.println("="+String(index));
    uint8_t nn = entry.read();
    Serial.println(nn,HEX);
    entry.close();
    index++;
  }
}
void loop() {
  // nothing happens after setup finishes.
}

 

bassizlink
Offline
Зарегистрирован: 06.02.2022

Переписал код выше, повторов нет кроме системной папки System.Впринцепи работа с этим каталогом не требуется.Не совсем понимаю, что в нем, полагаю, что это таблицы FAT  и они дублируются.Есть какие мысли по данному вопросу?Если кто не понял, то данный код не делает, то , что я описал выше.Он лишь проверяет работоспособность концепции открытия файла по его порядковому номеру.  

bassizlink
Offline
Зарегистрирован: 06.02.2022

Так же интересно, есть ли еще подводные камни по данному вопросу?

b707
Offline
Зарегистрирован: 26.05.2017

"тихо сам с собою..." ?

Вкратце попробуйте резюмировать, что сделали и в чем осталась проблема.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

bassizlink пишет:

Вариант вернуться к началу и пролистать N-1 мне не подходит, так как это очень медленно .

Тогда это тупик. Файловая система  набор функций для работы с ней построены так, что перебор возможен лишь в одном направлении.

Цитата:

Так же не подходит держать массив строк, так как памяти не хватит при большом количестве файлов и каталогов.

Ну, если Вам нужно вернуться на одну позицию, то именно эту одну позицию и нужно хранить. А если таких "возвратов на 1" может быть несколько, то приходится как-то оптимизировать - либо по скорости, либо по памяти. Размер памяти Ардуино практически не оставляет выбора: если это Uno/Nano/Mini/Micro/Leonardo, то любая попытка оптимизировать по скорости не поместится в память. Следовательно осаеются только 2 варианта:

1. Читать каждый раз с начала.

2. Самостоятельно переписывать работу с ФС, опираясь на функции чтения и записи сектора. (но "вернуться на 1" все равно получится только до начала сектора, т.е. в среднем на несколько записей. при переходе на "предыдущий сектор" его уже нужно будет искать с самого начала.)

bassizlink
Offline
Зарегистрирован: 06.02.2022

Переписал немного код.Он распечатывает имена файлов с любого индекса в обратном направлении.Установил индекс равный 455 и все распечаталось , с конца списка до нулевого файла.Вывод происходит шустро, в отличии от способа вернуться в начало и повторить перебор до N-1.Правда в коде есть ошибка, мне удалось исключить удаленные файлы из выводимого списка, но хоть и намного меньше все таки встречаются повторы, пока не понял почему.

#include <SPI.h>
#include <SD.h>

File root;
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  root = SD.open("/");
  uint32_t index = 455;
  while (true) {
    while (true){
      root.seek(32*index);
      uint8_t n = root.peek();
      
      if (n!=0xE5 && n!=0x05) {
        // файл не удален
        break;
      }
      index--;
    }
    File entry = root.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    Serial.print(entry.name());
    Serial.println("="+String(index));
    uint8_t nn = entry.peek();
    Serial.println(nn,HEX);
    entry.close();
    index--;
  }
}
void loop() {
  // nothing happens after setup finishes.
}

 

bassizlink
Offline
Зарегистрирован: 06.02.2022

andriano пишет:

bassizlink пишет:

Вариант вернуться к началу и пролистать N-1 мне не подходит, так как это очень медленно .

Тогда это тупик. Файловая система  набор функций для работы с ней построены так, что перебор возможен лишь в одном направлении.

Цитата:

Так же не подходит держать массив строк, так как памяти не хватит при большом количестве файлов и каталогов.

Ну, если Вам нужно вернуться на одну позицию, то именно эту одну позицию и нужно хранить. А если таких "возвратов на 1" может быть несколько, то приходится как-то оптимизировать - либо по скорости, либо по памяти. Размер памяти Ардуино практически не оставляет выбора: если это Uno/Nano/Mini/Micro/Leonardo, то любая попытка оптимизировать по скорости не поместится в память. Следовательно осаеются только 2 варианта:

1. Читать каждый раз с начала.

2. Самостоятельно переписывать работу с ФС, опираясь на функции чтения и записи сектора. (но "вернуться на 1" все равно получится только до начала сектора, т.е. в среднем на несколько записей. при переходе на "предыдущий сектор" его уже нужно будет искать с самого начала.)

Код работает, каждый раз возвращаться к началу не требуется.Осталось понять по какой причине есть повторы.  

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

bassizlink пишет:

Вывод происходит шустро, в отличии от способа вернуться в начало и повторить перебор до N-1.

Такое возможно только с нефрагментированным каталогом (в частном случае - корневым).

bassizlink
Offline
Зарегистрирован: 06.02.2022

Спасибо за комментарии.Правильно ли я понимаю, что некоторые повторения одних и тех же имен файлов при выводе в Serial, это просто фрагменты одного файла или каталога? Иначе говоря фрагментированные файлы и каталоги?Если ввести вместо "/"(корневого каталога) , "/имя папки", то такой способ работает.Почему нельзя прочитать по очереди фрагменты каталога, ведь это всего лишь набор байтов?Раз это читается в прямом направлении, то и должно читаться в обратном, к тому же я могу устанавливать указатель в любое место файла.Могут ли фрагменты файла или каталога находится в разных частях диска? Насколько я понял запись располагается последовательно друг за другом.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

1. Нет, фрагментация файла находит отражение только в FAT, в каталоге она никак не проявляется. А вот файлы с длинными именами занимают несколько "ячеек" в каталоге. Ну где-то же надо хранить символы этого самого длинного имени.

2. Дисковый накопитель принципиально невозможно читать "в любом месте", его можно читать исключительно посекторно, т.е. порциями по 512 байт. Соответственно "установить указатель в произвольном месте файла" - далеко не атомарная операция, которая может сопровождаться последовательным чтением нескольких секторов, расположенных как в текущем каталоге, так и в FAT. Файл не представляет собой непрерывную последовательность секторов, а потому сначала нужно узнать, каков номер сектора, содержащего следующий фрагмент файла. А это можно узнать лишь из FAT. А в FAT есть только ссылки "вперед" и нет ссылок "назад".

3. Да, фрагменты файла могут располагаться в разных частях диска. Именно это и называется фрагментацией файлов. А каталог - частный случай файла. И при банальном создании новых файлов каталог получается фрагментированным даже без удаления файлов. (в отличие от файлов, которые могут фрагментироваться лишь в случае, если на диске ранее удалялись файлы.)

4. Еще раз - нет, запись не обязана располагаться в секторах с последовательными номерами. Хотя и может. Это обстоятельство может существенно усложнить отладку: например, во всех тестовых примерах у Вас могут быть нефрагментированные файлы и неправильный алгоритм может работать с ними корректно, а как только появятся фрагментированные файлы, алгоритм "посыпется".

bassizlink
Offline
Зарегистрирован: 06.02.2022
File entry;
 dir.rewindDirectory()
for(uint64_t=0;i<N-2;i++){
  entry =  dir.openNextFile();
  entry.close();
}
entry =  dir.openNextFile();

Звучит печатьно.Как правильно организовать возврат к началу и перебор до N-1?Меня терзают сомнения, что я делаю, что то не так?У меня данный код работает очень медленно уже на 50-м индексе.

 

b707
Offline
Зарегистрирован: 26.05.2017

Вы бы настоящую задачу озвучили, не "читать файлы по индексу", а зачем вам это надо, мож кто и посоветует.

bassizlink
Offline
Зарегистрирован: 06.02.2022

по сути это и есть реальная задача, открыть предыдущий файл, вывести его имя на экран, вывести содержимое в Serial port.

bassizlink
Offline
Зарегистрирован: 06.02.2022

Правильно ли я понимаю, что если избегать длинных имен, то мой код будет работать?Есть идея как можно смоделировать ситуацию с файлом, записи в катологе, которого находятся в разных местах, файла каталога?Просто мне еще не попадаются такие записи файлов в файле каталогов.В конце концов меня устраивает формат имени файла 8.3, у меня экран на 13 символов. 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

1. Честно говоря, у меня так и не сложилось целостного впечатления о библиотеке SD. На мой взгляд, она не слишком логично построена. Ну и работать мне с ней приходилось всего пару-тройку проектов: всего необходимого в этих проектах я добился, а углубляться дальше желания не было. Поэтому дать советы типа "нужно нажать мышкой на одну кнопку, а потом на другую" я не могу. Ну и, соответственно, не могу ответить на вопрос "будет ли работать данный код?", не запустив этот код и не посмотрев результат.

2. Я бы настоятельно порекомендовал почитать о самой файловой системе. Ну хотя бы для того, чего от нее можно добиться, а чего - нет. Я разбирался с этим давно (очень задолго до появления Ардуино), так что частично мог забыть, а частично с тех пор мог измениться и сам стандарт FAT либо появиться его более новые версии.

3. Не совсем понял, какую ситуацию Вы хотите смоделировать. Если фрагментированных файлов - то записать на карту много мелких файлов, после чего некоторые из них удалить в случайном порядке, а потом дописать на карту файлы покрупнее - они и будут фрагментированные. "Мелкие и "крупные", естественно, по отношению к размеру кластера. Если фрагментированный каталог, то достаточно просто последовательно писать в него много мелких (или крупных) файлов.

4. Корневой каталог всегда нефрагментирован, но у него ограниченный размер, и изменить его, в отличие от вложенного каталога, невозможно.

bassizlink
Offline
Зарегистрирован: 06.02.2022

Спасибо за совет.Читал, читаю.К сожалению не сразу все понятно.Буду пробовать.

bassizlink
Offline
Зарегистрирован: 06.02.2022

Хотелось найти способ фильтровать все дефрагментированные файлы, за исключением начального сегмента, каждого файла.Полагаю, что их можно отличить.Паралельно попробовал перебрать до N-1 при помощи другой библиотеки SDFat, работает шустро.Проблема решена.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Способ фильтрации, естественно, существует: фрагментированным является файл, у которого в цепочке последовательных кластеров хоть раз встречается ситуация, что номер следующего кластера не равен номеру предыдущего плюс единица.

Другими словами, нужно анализировать таблицу FAT.