2014-03-30 1 views
3

Google Play에 기기 정보 앱이 있으며 앱에 저장 용량 정보가 있습니다. Android 4.4에서 외부 SD 카드에 액세스하는 것과 관련하여 몇 가지 변경 사항이 있음을 확인했습니다. 내부는 나에게 문제가되지 않는 것 같습니다. 제 질문은 KitKat에서 SD 카드의 크기를 어떻게 안정적으로 얻을 수 있습니까?KitKat에서 SDard 경로 및 크기 얻기 4.4.2

Android의 이전 버전에서 정상적으로 작동하므로 필요한 권한이 나열되어 있습니다. 나는 여기에서 수색 했으므로, 나는 항상 같은 오류 중 하나를 얻는 것처럼 보입니다. SD 카드에 글을 쓸 필요가 없으며 크기에 대한 읽기만 가능합니다.

나는 StorageUtils에서 온 클래스이므로 죄송합니다. 기억이 안납니다.

public class StorageUtils { 

private static final String TAG = "StorageUtils"; 

public static class StorageInfo { 

    public final String path; 
    public final boolean internal; 
    public final boolean readonly; 
    public final int display_number; 

    StorageInfo(String path, boolean internal, boolean readonly, 
      int display_number) { 
     this.path = path; 
     this.internal = internal; 
     this.readonly = readonly; 
     this.display_number = display_number; 
    } 
} 

public static ArrayList<StorageInfo> getStorageList() { 

    ArrayList<StorageInfo> list = new ArrayList<StorageInfo>(); 
    String def_path = Environment.getExternalStorageDirectory().getPath(); 
    boolean def_path_internal = !Environment.isExternalStorageRemovable(); 
    String def_path_state = Environment.getExternalStorageState(); 
    boolean def_path_available = def_path_state 
      .equals(Environment.MEDIA_MOUNTED) 
      || def_path_state.equals(Environment.MEDIA_MOUNTED_READ_ONLY); 
    boolean def_path_readonly = Environment.getExternalStorageState() 
      .equals(Environment.MEDIA_MOUNTED_READ_ONLY); 
    BufferedReader buf_reader = null; 
    try { 
     HashSet<String> paths = new HashSet<String>(); 
     buf_reader = new BufferedReader(new FileReader("/proc/mounts")); 
     String line; 
     int cur_display_number = 1; 
     Log.d(TAG, "/proc/mounts"); 
     while ((line = buf_reader.readLine()) != null) { 
      Log.d(TAG, line); 
      if (line.contains("vfat") || line.contains("/mnt")) { 
       StringTokenizer tokens = new StringTokenizer(line, " "); 
       String unused = tokens.nextToken(); // device 
       String mount_point = tokens.nextToken(); // mount point 
       if (paths.contains(mount_point)) { 
        continue; 
       } 
       unused = tokens.nextToken(); // file system 
       List<String> flags = Arrays.asList(tokens.nextToken() 
         .split(",")); // flags 
       boolean readonly = flags.contains("ro"); 

       if (mount_point.equals(def_path)) { 
        paths.add(def_path); 
        list.add(new StorageInfo(def_path, def_path_internal, 
          readonly, -1)); 
       } else if (line.contains("/dev/block/vold")) { 
        if (!line.contains("/mnt/secure") 
          && !line.contains("/mnt/asec") 
          && !line.contains("/mnt/obb") 
          && !line.contains("/dev/mapper") 
          && !line.contains("tmpfs")) { 
         paths.add(mount_point); 
         list.add(new StorageInfo(mount_point, false, 
           readonly, cur_display_number++)); 
        } 
       } 
      } 
     } 

     if (!paths.contains(def_path) && def_path_available) { 
      list.add(new StorageInfo(def_path, def_path_internal, 
        def_path_readonly, -1)); 
     } 

    } catch (FileNotFoundException ex) { 
     ex.printStackTrace(); 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
    } finally { 
     if (buf_reader != null) { 
      try { 
       buf_reader.close(); 
      } catch (IOException ex) { 
      } 
     } 
    } 
    return list; 
} 

public static String getReadableFileSize(long bytes, boolean si) { 
    int unit = si ? 1000 : 1024; 
    if (bytes < unit) 
     return bytes + " B"; 
    int exp = (int) (Math.log(bytes)/Math.log(unit)); 
    String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) 
      + (si ? "" : "i"); 
    return String.format("%.1f %sB", bytes/Math.pow(unit, exp), pre); 
} 

@SuppressLint("NewApi") 
public static long getFreeSpace(String path) { 
    StatFs statFs = new StatFs(path); 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { 
     long sdAvailSize = statFs.getFreeBlocksLong() 
       * statFs.getBlockSizeLong(); 
     return sdAvailSize; 
    } else { 
     @SuppressWarnings("deprecation") 
     double sdAvailSize = (double) statFs.getFreeBlocks() 
       * (double) statFs.getBlockSize(); 

     return (long) sdAvailSize; 
    } 
} 

public static long getUsedSpace(String path) { 
    return getTotalSpace(path) - getFreeSpace(path); 
} 

@SuppressLint("NewApi") 
public static long getTotalSpace(String path) { 
    StatFs statFs = new StatFs(path); 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { 
     long sdTotalSize = statFs.getBlockCountLong() 
       * statFs.getBlockSizeLong(); 
     return sdTotalSize; 
    } else { 
     @SuppressWarnings("deprecation") 
     double sdTotalSize = (double) statFs.getBlockCount() 
       * statFs.getBlockSize(); 

     return (long) sdTotalSize; 
    } 
} 

/** 
* getSize()[0] is /mnt/sdcard. getSize()[1] is size of sd (example 12.0G), 
* getSize()[2] is used, [3] is free, [4] is blksize 
* 
* @return 
* @throws IOException 
*/ 
public static String[] getSize() throws IOException { 
    String memory = ""; 
    Process p = Runtime.getRuntime().exec("df /mnt/sdcard"); 
    InputStream is = p.getInputStream(); 
    int by = -1; 
    while ((by = is.read()) != -1) { 
     memory += new String(new byte[] { (byte) by }); 
    } 
    for (String df : memory.split("/n")) { 
     if (df.startsWith("/mnt/sdcard")) { 
      String[] par = df.split(" "); 
      List<String> pp = new ArrayList<String>(); 
      for (String pa : par) { 
       if (!pa.isEmpty()) { 
        pp.add(pa); 
       } 
      } 
      return pp.toArray(new String[pp.size()]); 

     } 
    } 
    return null; 
} 

} 

그리고 여기 SDcard 경로와 크기를 표시하려고하는 일부분입니다.

public class CpuMemFragment extends Fragment { 
// CPU 
String devCpuInfo; 
TextView tvCpuInfo; 

// RAM 
String devRamInfo; 
TextView tvRamInfo; 

// Storage 
String devStorageA, devStorageB; 
TextView tvStorageAName, tvStorageA, tvStorageB, tvStorageBName; 

AdView adView; 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 

    View rootView = inflater.inflate(R.layout.cpu_mem, container, false); 

    return rootView; 
} 

@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
    // TODO Auto-generated method stub 
    super.onActivityCreated(savedInstanceState); 

    // *** CPU *** 
    // 
    devCpuInfo = readCpuInfo(); 
    // 
    // ################################# 

    // *** RAM *** 
    // 
    devRamInfo = readTotalRam(); 
    // 
    // ################################# 

    // *** STORAGE *** 
    // 

    ArrayList<StorageInfo> storageInfoList = StorageUtils.getStorageList(); 

    tvStorageAName = (TextView) getView().findViewById(R.id.tvStorageAName); 

    tvStorageBName = (TextView) getView().findViewById(R.id.tvStorageBName); 

    if (storageInfoList.size() > 0) { 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT 
       && !storageInfoList.get(0).internal) { 
      kitKatWorkaround(0); 
     } 
     tvStorageAName.setText(storageInfoList.get(0).path); 

     devStorageA = StorageUtils.getReadableFileSize(
       (StorageUtils.getUsedSpace(storageInfoList.get(0).path)), 
       true) 
       + "/" 
       + StorageUtils.getReadableFileSize((StorageUtils 
         .getTotalSpace(storageInfoList.get(0).path)), true); 

     if (storageInfoList.size() > 1) { 
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT 
        && !storageInfoList.get(0).internal) { 
       kitKatWorkaround(1); 
      } 
      tvStorageBName.setText(storageInfoList.get(1).path); 

      devStorageB = StorageUtils.getReadableFileSize(
        StorageUtils.getUsedSpace(storageInfoList.get(1).path) 
          + (StorageUtils.getUsedSpace("system/")), true) 
        + "/" 
        + StorageUtils.getReadableFileSize((StorageUtils 
          .getTotalSpace(storageInfoList.get(1).path)), 
          true); 
     } else { 
      devStorageB = "N/A"; 
     } 
    } else { 
     devStorageA = "N/A"; 
     devStorageB = "N/A"; 
    } 
    // 
    // ################################# 

    // CPU 
    tvCpuInfo = (TextView) getView().findViewById(R.id.tvCpuInfo); 
    tvCpuInfo.setText(devCpuInfo); 
    // 
    // ################################# 

    // RAM 
    tvRamInfo = (TextView) getView().findViewById(R.id.tvRamInfo); 
    tvRamInfo.setText(devRamInfo); 
    // 
    // ################################# 

    // STORAGE 
    tvStorageA = (TextView) getView().findViewById(R.id.tvStorageA); 
    tvStorageA.setText(devStorageA); 

    tvStorageB = (TextView) getView().findViewById(R.id.tvStorageB); 
    tvStorageB.setText(devStorageB); 
    // 
    // ################################# 

    // Look up the AdView as a resource and load a request. 
    adView = (AdView) getActivity().findViewById(R.id.adCpuMemBanner); 
    AdRequest adRequest = new AdRequest.Builder().build(); 
    adView.loadAd(adRequest); 
} 

@Override 
public void onPause() { 
    if (adView != null) { 
     adView.pause(); 
    } 
    super.onPause(); 
} 

@Override 
public void onResume() { 
    super.onResume(); 
    if (adView != null) { 
     adView.resume(); 
    } 
} 

@Override 
public void onDestroy() { 
    if (adView != null) { 
     adView.destroy(); 
    } 
    super.onDestroy(); 
} 

private static synchronized String readCpuInfo() { 
    ProcessBuilder cmd; 
    String result = ""; 

    try { 
     String[] args = { "/system/bin/cat", "/proc/cpuinfo" }; 
     cmd = new ProcessBuilder(args); 

     Process process = cmd.start(); 
     InputStream in = process.getInputStream(); 
     byte[] re = new byte[1024]; 
     while (in.read(re) != -1) { 
      System.out.println(new String(re)); 
      result = result + new String(re); 
     } 
     in.close(); 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
    } 
    return result; 
} 

public static synchronized String readTotalRam() { 
    String load = ""; 
    try { 
     RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r"); 
     load = reader.readLine(); 
     reader.close(); 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
    } 
    return load; 
} 

public void kitKatWorkaround(int index) { 
    String path1 = Environment.getExternalStorageDirectory().getPath(); 

      //Storage A 
    if (index == 0) { 

     tvStorageAName.setText(path1); 

     devStorageA = StorageUtils.getReadableFileSize(
       (StorageUtils.getUsedSpace(path1)), true) 
       + "/" 
       + StorageUtils.getReadableFileSize(
         (StorageUtils.getTotalSpace(path1)), true); 
    } 

      //Storage B 
    if (index == 1) { 
     tvStorageBName.setText(path1); 

     devStorageB = StorageUtils.getReadableFileSize(
       StorageUtils.getUsedSpace(path1)), true) 
       + "/" 
       + StorageUtils.getReadableFileSize(
         (StorageUtils.getTotalSpace(path1)), true); 

    } 
} 
} 

이것은 EACCES error 또는 킷캣에 invalid path (access denied) 초래한다. 도와 주시고 시간 내 주셔서 대단히 감사드립니다.

답변

2

Context.getExternalFilesDirs() 또는 Context.getExternalCacheDirs()을 호출하여 모든 공유 저장 장치를 찾을 수 있습니다. 그런 다음 File.getUsableSpace()으로 전화하거나 android.os.StatFs을 사용하여 각 위치에서 사용 가능한 디스크 공간을 확인할 수 있습니다.

이러한 API는 지원 라이브러리의 ContextCompat에서도 사용할 수 있으며 KitKat 전 장치에서 원활하게 작동합니다.

+0

이것은 지금까지 작동하지만 SDcard 루트의 경로를 얻는 방법은 무엇입니까? 'tvStorageAName.setText (sdCard1.getAbsolutePath(). ("안드로이드/데이터 /"+ getActivity(). getPackageName() + "/ 캐시", "")); 편집 : 이것은 내 노트 3 장치에서 잘 작동하는 것 같습니다. 고마워, 다른 사람들에게도 도움이되기를 바랍니다 :) Happy Coding! – MattMatt