2012-04-23 7 views
5

Tôi đang tìm cách phát hiện và truy cập thẻ sd có thể tháo rời trên nhiều thiết bị Android khác nhau (Samsung, Motorola, LG, Sony, HTC).Cách truy cập bộ nhớ di động trên thiết bị Android?

Tôi cũng cần phải tương thích với 2.2 vì vậy Environment.isExternalStorageRemovable() không khả dụng đối với tôi.

Motorola có thư viện riêng của mình, và cho Samsung Tôi có thể phát hiện sự tồn tại của /external_sd/

tôi không có đầu mối cho phần còn lại của họ. Ví dụ, tôi đã thấy một số /_ExternalSD/ trên một số LG nhưng thư mục vẫn còn ngay cả khi SD bị xóa.

Một câu hỏi bonus: các ACTION_MEDIA_MOUNTED ý định sẽ được phát sóng cho bất kỳ trong số họ

Bất kỳ gợi ý về vấn đề này sẽ rất hữu ích.

+0

Bất kỳ thứ gì ngoài các phương pháp trên 'Môi trường' đều nằm ngoài giới hạn của SDK và sẽ không đáng tin cậy. – CommonsWare

Trả lời

0

Những khả năng này có sẵn trong tất cả các phiên bản Android:

  • Để có được thư mục của ứng dụng vào bộ nhớ ngoài, hãy gọi Context.getExternalFilesDir.

  • Hãy ghi nhớ rằng ứng dụng của bạn cần sự cho phép rõ ràng để truy cập lưu trữ bên ngoài, và rằng bạn nên kiểm tra xem nó có sẵn thông qua Environment.getExternalStorageState

  • Và vâng, ACTION_MEDIA_MOUNTED sẽ được phát sóng mỗi khi phương tiện di động trở nên dễ tiếp cận (Bạn nên cũng nghe theo số ACTION_MEDIA_EJECTACTION_MEDIA_REMOVED)

+0

Cảm ơn Tony nhưng điều này sẽ chỉ trả về/mnt/sdcard mà không phải là thiết bị lưu trữ di động. Tôi đã chỉnh sửa câu hỏi của tôi để nó được xây dựng chính xác. – znat

+0

Có, bộ nhớ ngoài * thường *, nhưng không * luôn * có thể tháo rời. Trường hợp sử dụng chính xác của bạn là gì? –

+0

Ứng dụng phải cung cấp lựa chọn thiết bị lưu trữ để tải xuống. Thông thường bên trong và bên ngoài thiết bị lưu trữ di động. Từ những gì tôi thấy sự tách biệt không rõ ràng. Ví dụ. Samsung gắn thẻ SD có thể tháo rời trên/mnt/sdcard/external_sd. LG trên/mnt/sdcard/_ExternalSD/nhưng các thư mục và một số tập tin vẫn còn ngay cả khi tháo rời được cắm phít. Điều này gợi ý rằng không có sự phân tách hợp lý – znat

3

Đây là lớp tôi sử dụng để tìm tất cả thẻ SD trên thiết bị; được tích hợp và tháo lắp. Tôi đã sử dụng nó trên Ice Cream Sandwich, nhưng nó sẽ hoạt động ở mức 2x.

public class GetRemovableDevice { 

private final static String TAG = "GetRemoveableDevice"; 

public GetRemovableDevice() { 
} 

public static String[] getDirectories() { 
    MyLog.d(TAG, "getStorageDirectories"); 
    File tempFile; 
    String[] directories = null; 
    String[] splits; 
    ArrayList<String> arrayList = new ArrayList<String>(); 
    BufferedReader bufferedReader = null; 
    String lineRead; 

    try { 
     arrayList.clear(); // redundant, but what the hey 
     bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

     while ((lineRead = bufferedReader.readLine()) != null) { 
      MyLog.d(TAG, "lineRead: " + lineRead); 
      splits = lineRead.split(" "); 

      // System external storage 
      if (splits[1].equals(Environment.getExternalStorageDirectory() 
        .getPath())) { 
       arrayList.add(splits[1]); 
       MyLog.d(TAG, "gesd split 1: " + splits[1]); 
       continue; 
      } 

      // skip if not external storage device 
      if (!splits[0].contains("/dev/block/")) { 
       continue; 
      } 

      // skip if mtdblock device 

      if (splits[0].contains("/dev/block/mtdblock")) { 
       continue; 
      } 

      // skip if not in /mnt node 

      if (!splits[1].contains("/mnt")) { 
       continue; 
      } 

      // skip these names 

      if (splits[1].contains("/secure")) { 
       continue; 
      } 

      if (splits[1].contains("/mnt/asec")) { 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      tempFile = new File(splits[1]); 
      if (!tempFile.exists()) { 
       continue; 
      } 
      if (!tempFile.isDirectory()) { 
       continue; 
      } 
      if (!tempFile.canRead()) { 
       continue; 
      } 
      if (!tempFile.canWrite()) { 
       continue; 
      } 

      // Met all the criteria, assume sdcard 
      arrayList.add(splits[1]); 
     } 

    } catch (FileNotFoundException e) { 
    } catch (IOException e) { 
    } finally { 
     if (bufferedReader != null) { 
      try { 
       bufferedReader.close(); 
      } catch (IOException e) { 
      } 
     } 
    } 

    // Send list back to caller 

    if (arrayList.size() == 0) { 
     arrayList.add("sdcard not found"); 
    } 
    directories = new String[arrayList.size()]; 
    for (int i = 0; i < arrayList.size(); i++) { 
     directories[i] = arrayList.get(i); 
    } 
    return directories; 
} 

}

Các MyLog.d là một lớp dấu vết mà mở rộng Log.d - nó có thể bị loại bỏ.

Lớp đọc/proc/mounts/và:

  1. kiểm tra xem nếu tên đường dẫn là thư mục sdcard nội
  2. kiểm tra để xem nếu nó là một thiết bị khối
  3. bỏ qua mtdblock thiết bị
  4. bỏ qua bất cứ điều gì mà không được gắn kết
  5. bỏ qua thư mục an toàn và ASEC
  6. làm cho chắc chắn nó tồn tại, là một thư mục, và đọc/viết có thể truy cập

Nếu tất cả điều này phù hợp, nó giả định rằng bạn có thẻ sd và thêm đường dẫn vào danh sách mảng. Nó trả về một chuỗi các tên đường dẫn.

Để gọi getDirectories chức năng, mã một cái gì đó tương tự như:

String[] sdcardDirectories = GetRemoveableDevice.getDirectories(); 

Các đường dẫn trở lại có thể được sử dụng để tạo ra một danh sách lựa chọn sử dụng, quét một tập tin, hoặc bất cứ điều gì.

Cuối cùng, đây là hai dòng MyLog.d từ một thử nghiệm giả lập (dòng thứ hai là sdcard emulator):

09-19 15: 57: 12,511: D/GetRemoveableDevice (651): lineRead:/dev/block/mtdblock2/cache yaffs2 rw, nosuid, nodev 0 0

09-19 15: 57: 12.511: D/GetRemoveableDevice (651): lineRead:/dev/block/vold/179: 0/mnt/sdcard vfat rw, dirsync, nosuid, nodev, noexec, uid = 1000, gid = 1015, fmask = 0702, dmask = 0702, allow_utime = 0020, codepage = cp437, iocharset = iso8859-1, tên ngắn = hỗn hợp, utf8, lỗi = remount -ro 0 0

+0

Rất tiếc. Tôi quên đề cập đến việc kiểm tra trạng thái đọc/ghi loại bỏ các sdcard chưa được gắn kết mà vẫn có một mục nhập trong thư mục/mnt /. –

+0

Tôi biết chủ đề này là cũ, nhưng tôi đang chuyển đổi một số mã phát hiện lưu trữ vào một thư viện mục đích chung và muốn phân biệt giữa bộ nhớ ngoài là vĩnh viễn và đó là thực sự có thể tháo rời. Tôi không biết liệu giải pháp của bạn có đáp ứng được yêu cầu đó không?Có vẻ như câu lệnh "if" đầu tiên trong vòng lặp của bạn sẽ lưu trữ bất kỳ sự xuất hiện nào của đường dẫn được trả về bởi "getExternalStorageDirectory()", thường xuyên hơn không phải là không thể di chuyển được, đúng không? –

+0

Xin lỗi quá lâu. Đầu xuống bàn phím làm việc trên dự án. Để trả lời, có đường dẫn từ getExtenalStorageDirectory thường là sdcard không thể kết nối. Mục đầu tiên trong danh sách được trả về là thẻ sd getExternal. Nếu danh sách có nhiều mục nhập, hãy sử dụng mục nhập thứ hai hoặc sau đó. Bạn cũng có thể kiểm tra xem nó có thể được tháo dỡ hay không. Ngoài ra, bạn có thể thực hiện một dự án đơn giản để hiển thị danh sách (và bất cứ điều gì khác bạn muốn) và sau đó kiểm tra những gì sẽ xảy ra khi bạn loại bỏ và thay thế sdcard tháo rời (s). –

1

Dựa trên lớp Howards tôi đã thực hiện một số sửa đổi để làm cho nó hoạt động trên Galaxy S3.

  1. Environment.getExternalStorageDirectory() trả về bộ nhớ trong trên S3.
  2. lưu trữ có thể tháo rời được không nhất thiết phải gắn dưới/mnt
  3. phương tiện truyền thông có thể tháo rời phải có vfat hệ thống tập tin

_

public static String getDirectory() { 
     Log.d(TAG, "getStorageDirectories"); 
     File tempFile; 
     String[] splits; 
     ArrayList<String> arrayList = new ArrayList<String>(); 
     BufferedReader bufferedReader = null; 
     String lineRead; 

     try { 
      arrayList.clear(); // redundant, but what the hey 
      bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

      while ((lineRead = bufferedReader.readLine()) != null) { 
       Log.d(TAG, "lineRead: " + lineRead); 
       splits = lineRead.split(" "); 

       // skip if not external storage device 
       if (!splits[0].contains("/dev/block/")) { 
        continue; 
       } 

       // skip if mtdblock device 
       if (splits[0].contains("/dev/block/mtdblock")) { 
        continue; 
       } 

       // skip if not in vfat node 
       if (!splits[2].contains("vfat")) { 
        continue; 
       } 

       // skip these names 
       if (splits[1].contains("/secure")) { 
        continue; 
       } 

       if (splits[1].contains("/mnt/asec")) { 
        continue; 
       } 

       // Eliminate if not a directory or fully accessible 
       tempFile = new File(splits[1]); 
       if (!tempFile.exists()) { 
        continue; 
       } 
       if (!tempFile.isDirectory()) { 
        continue; 
       } 
       if (!tempFile.canRead()) { 
        continue; 
       } 
       if (!tempFile.canWrite()) { 
        continue; 
       } 

       // Met all the criteria, assume sdcard 
       return splits[1]; 
      } 

     } catch (FileNotFoundException e) { 
     } catch (IOException e) { 
     } finally { 
      if (bufferedReader != null) { 
       try { 
        bufferedReader.close(); 
       } catch (IOException e) { 
       } 
      } 
     } 

     return null; 
    } 
+0

tôi tin rằng đây cũng không phải là cách được khuyến cáo bởi google. – Raghunandan

+2

Tôi đồng ý rằng đó là một hack. Nhưng đây là hack sạch nhất mà tôi đã thấy. Nếu bạn tìm thấy một cách thích hợp xin vui lòng cho chúng tôi biết. – tmanthey

+0

hình thức khác nhau như thế nào khi tôi đăng – Raghunandan

1

Dựa trên 2 lớp trình bày ở trên tôi sửa đổi các lớp sâu hơn về nhận thấy rằng tất cả các lưu trữ di động bên ngoài trên một số điện thoại và máy tính bảng mà tôi có thể tìm thấy được gắn bằng cách sử dụng vold, daemon khối lượng gắn kết.

  // skip if not external storage device 
      if (!splits[0].contains("vold")) { 
       continue; 
      } 

      if (splits[1].contains("/mnt/asec")) { 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      tempFile = new File(splits[1]); 
      if (!tempFile.exists()) { 
       continue; 
      } 
      if (!tempFile.isDirectory()) { 
       continue; 
      } 
      if (!tempFile.canRead()) { 
       continue; 
      } 
      if (!tempFile.canWrite()) { 
       continue; 
      } 

      // Met all the criteria, assume sdcard 
      arrayList.add(splits[1]); 
+0

Cảm ơn bạn đã chia sẻ những gì bạn đã học. +1. Hãy nhớ rằng "ở trên" không phải là tài sản ổn định của câu trả lời ... hiện có 3 lớp khác trên trang này và 2 lớp bạn đang đề cập có thể xuất hiện bên dưới trang của bạn khi ai đó xem trang này. – LarsH

0

Đây là phương pháp tôi đã tạo và đang sử dụng. Điều này đã làm việc trên Samsung Galaxy S4, Samsung Galaxy Note 3 và Sony Xperia Z2.

private static String[] getRemovableStoragePaths() { 
    String[] directories; 
    String[] splits; 
    ArrayList<String> pathList = new ArrayList<String>(); 
    BufferedReader bufferedReader = null; 
    String lineRead; 

    try { 
     bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

     while ((lineRead = bufferedReader.readLine()) != null) { 
      Log.d(TAG, "lineRead: " + lineRead); 
      splits = lineRead.split(" "); 
      Log.d(TAG, "Testing path: " + splits[1]); 

      if (!splits[1].contains("/storage")) { 
       continue; 
      } 

      if (splits[1].contains("/emulated")) { 
       // emulated indicates an internal storage location, so skip it. 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      Log.d(TAG, "Path found: " + splits[1]); 

      // Met all the criteria, assume sdcard 
      pathList.add(splits[1]); 
     } 

    } catch (FileNotFoundException e) { 
    } catch (IOException e) { 
    } finally { 
     if (bufferedReader != null) { 
      try { 
       bufferedReader.close(); 
      } catch (IOException e) { 
      } 
     } 
    } 

    // Send list back to caller 

    if (pathList.size() == 0) { 
     pathList.add("sdcard not found"); 
    } else { 
     Log.d(TAG, "Found potential removable storage locations: " + pathList); 
    } 
    directories = new String[pathList.size()]; 
    for (int i = 0; i < pathList.size(); i++) { 
     directories[i] = pathList.get(i); 
    } 
    return directories; 
}