Отримання шляху до карти пам’яті sd card на android
Розробляючи додаток для проведення змагань, я зіткнувся з проблемою зберігання бази даних. Проблема полягала в тому, як мені визначити зовнішню карту пам'яті. В цілому пошук в мережі точної відповіді не дав. Тому, об'єднавши всі знайдені результати, я зібрав свій клас. Якщо кому цікаво, дивимося під катом.
Отже, почнемо з теорії.
Термінологія
Гугл нам говорить, що є такі поняття:
До версії KitKat 4.4 API не надавало функціоналу для отримання шляхів до зовнішньої пам'яті. Починаючи з цієї версії (API 19) з'явилася функція public abstract File [] getExternalFilesDirs (String type), яка повертає масив рядків з шляхами до внутрішньої і зовнішньої пам'яті. Але як же бути з нашої SD Card, яка вставлена в слот? Шлях до неї ми знову не можемо отримати.
Результати пошуку
Щоб відповісти на поставлене запитання я звернувся до всезнаючого Гуглу. Але і він мені не дав чіткої відповіді. Було розглянуто безліч варіантів визначення від використання стандартних функцій, які ведуть до зовнішньої пам'яті, але нічого спільного з видаляються пристроями зберігання даних вони не мають, до обробки правил монтування пристроїв (Android же на ядрі Linux працює). В останніх випадках були використані «зашиті» шляху до папки з прімонтірованимі пристроями (в різних версіях ця директорія різна). Не варто забувати, що від версії до версії правила монтування змінюються.
В кінцевому підсумку я вирішив об'єднати всі отримані знання і написав свій клас, який може нам повернути шляху до зовнішніх і видаляється пристроїв.
опис коду
Був створений клас MountDevice. який містить в собі шлях до пристрою, тип пристрою і якийсь хеш.
Типів пристроїв виділено два (внутрішню пам'ять я не став чіпати, так як до неї доступ можна отримати через API системи).
І був створений клас StorageHelper. який і здійснює пошук доступних карт пам'яті.
У класі StorageHelper реалізовано два способи пошуку - через системне оточення (Environment) і з використанням утиліти Linux mount. а точніше результату її виконання.
Спосіб перший - Environment
При роботі з оточенням я використовую стандартну функцію getExternalStorageDirectory () для отримання інформації про зовнішній пам'яті. Щоб отримати інформацію про видаляється пам'яті, я використовую змінну оточення "SECONDARY_STORAGE".
Зовнішня пам'ять завжди одна і зазвичай завжди є, тому перевіряємо її на Новомосковскемость, обчислюємо хеш і запам'ятовуємо. Видаляється пам'яті може бути багато, тому необхідно отриманий рядок розбити по разделителю і перевіряти кожне значення.
Варіант рішення взято зі stackoverflow. Відповідь десь там внизу.
Спосіб другий - mount
Так як у мене довго не виходило змусити систему мені сказати шлях до видаляється пам'яті, я вирішив шукати в сторону примонтировать пристроїв. В системі є файли конфігурації, в яких описані правила монтування зовнішніх пристроїв. Все б добре, але на Android версії 4. * до цього файлу простим смертним доступу немає, тому розглядати цей спосіб не буду.
Повернемося до утиліти mount. При запуску без параметрів команда повертає список змонтованих файлових систем. Видаляються пристрої мають зазвичай формат файлової системи FAT, то будемо виділяти рядки, в яких є характеристика "fat". Зовнішня пам'ять буде характеризуватися параметром "fuse".
Примітка: при використанні такого способу не завжди коректно (швидше за все я щось не врахував) визначаються типи смотнтірованних пристроїв. Різницю помічав на різних версіях Android. Тому цей спосіб можна використовувати як додатковий.
Варіант рішення взято зі stackoverflow. Відповідей там кілька приблизно однакових.
про дублювання
Багато хто помічав в директорії монтування пристроїв таку картину:
І що саме цікаво, все це одна і та ж зовнішня карта пам'яті. Таке дроблення починається з версії Jelly Bean і зроблено це для підтримки багато режиму роботи системи. Більш детально тут. І ось, щоб не отримувати одну й ту ж саму карту пам'яті як різні пристрої, необхідний спосіб визначення ідентичності. Якби був доступ до конфігурації монтування, то і питань не було. Але доступу немає. Тому я тут підглянув рішення з розрахунком хеша для кожного пристрою:
- створюємо StringBuilder
- записуємо в нього загальний розмір пристрою і частинка простору пристрою
- обходимо вміст кореня пристрої
- записуємо ім'я каталогу
- записуємо ім'я файлу і розмір
- обчислюємо hash
Своя функція розрахунку хеша calcHash
приклад використання
висновок
Докладні міркування з цього питання розуміння пам'яті в Android, деякі поради можна прочитати тут.
Вихідний код всього класу розташований ще ніде не розташований. Днями постараюся розмістити на gitHub.
Хто ще якими способами користується?