- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在 Google Play 上有一个设备信息应用程序,在该应用程序中我有存储信息。我知道在 Android 4.4 中,在访问外部 SD 卡方面发生了一些变化。内部似乎没有给我一个问题。我的问题是,如何可靠地获取 KitKat 上 SD 卡的大小?
我列出了所需的权限,因为这在早期版本的 Android 上运行良好。我在这里搜索过 SO,但我似乎总是遇到相同的错误之一。我不需要写入 SD 卡,只需要读取大小可用性。
我有一个来自 SO 的 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;
}
}
这是我尝试显示 SD 卡路径和大小的 fragment 。
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 错误
,或 KitKat 上的无效路径(拒绝访问)
。请提供帮助,非常感谢您抽出宝贵时间。
最佳答案
您可以通过调用Context.getExternalFilesDirs()
或Context.getExternalCacheDirs()
找到所有共享存储设备。然后,您可以调用 File.getUsableSpace()
或使用 android.os.StatFs
检查每个位置的可用磁盘空间。
这些 API 也可在支持库的 ContextCompat
中使用,以便在 pre-KitKat 设备上无缝工作。
关于android - 在 KitKat 4.4.2 中获取 SDard(s) 路径和大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22739668/
这个问题在这里已经有了答案: Why don't Java's +=, -=, *=, /= compound assignment operators require casting? (11 个
我搜索了很多,但没有一个链接能帮助我解决这个问题。我得到了 ORA-21500: internal error code, arguments: [%s], [%s], [%s], [%s], [%s
我正在做 RegexOne 正则表达式教程,它有一个 question关于编写正则表达式以删除不必要的空格。 教程中提供的解决方案是 We can just skip all the starting
([\s\S]+|\s?) 中 |\s? 的目的或作用是什么?如果没有它,表达式会不会与 ([\s\S]+) 相同? 最佳答案 这不是完全相同的。 ([\s\S]+|\s?) 会匹配空字符串,而 ([
这个正则表达式有一组还是两组? 我正在尝试使用第二组访问 bookTitle 但出现错误: Pattern pattern = Pattern.compile("^\\s*(.*?)\\s+-\\s+
在 C 中给定一个字符串指针 s,下面的迭代会做什么?即它以什么方式遍历字符串? for (++s ; *s; ++s); 最佳答案 for (++s ; *s;++s) 表示 将指针 s 递增到字符
我正在用一个 node.js 应用程序解析一个大列表并有这段代码 sizeCode = dbfr.CN_DESC.split('\s+-\s*|\s*-\s+') 这似乎不起作用,因为它返回了 [ '
我正在编写一个简单的字符串连接程序。 该程序按照我发布的方式运行。但是,我首先使用以下代码编写它来查找字符串的结尾: while (*s++) ; 但是,这个方法并没有奏效。我传递给它的字符串
这个问题已经有答案了: What does (?和aramchand来自Mohandas Karamchand G 因此,在使用这些匹配来分割字符串后,您最终会得到 {"M", "K", "G"} 注
我正在尝试转换 Map到 List使用 lambda。 本质上,我想将键和值与 '=' 连接起来之间。这看起来微不足道,但我找不到如何去做。 例如 Map map = new HashMap<>();
我正在经历 K & R,并且在递增指针时遇到困难。练习 5.3(第 107 页)要求您使用指针编写一个 strcat 函数。 在伪代码中,该函数执行以下操作: 将 2 个字符串作为输入。 找到字符串
在下面的代码中,pS 和 s.pS 在最后一行是否保证相等?也就是说,在语句S s = S();中,是否可以确定不会构造一个临时的S? #include using namespace std; s
演示示例代码: public void ReverseString(char[] s) { for(int i = 0, j = s.Length-1; i < j; i++, j--){
我一直在寻找类似于 .NET examples 中的示例的 PowerShell 脚本.取一个 New-TimeSpan 并显示为 1 天 2 小时 3 分钟 4 秒。排除其零的地方,在需要的地方添加
def func(s): s = s + " is corrected" return s string_list = ["She", "He"] for s in string_li
我是 python 的新手。当我在互联网上搜索 lambda 时。我在 lambda_functions 中找到了这个声明. processFunc = collapse and (lambda s:
我最近开始学习正则表达式,并试图为上面的问题写一个正则表达式。如果限制只放在一个字母上(例如不超过 2 个“b”),这并不困难。 那么答案就是:a* c*(b|ε)a* c*(b|ε)a* c* 但是
当我运行 npm install 时出现以下错误,但我无法修复它。 我试过:npm install -g windows-build-tools 也没有修复这个错误 ERR! configure
有很多有趣的haskell网上可以找到片段。 This post可以在 this (awesome) Stack Overflow question 下找到. The author写道: discou
我知道以下三行代码旨在将字符串提取到$ value中并将其存储在$ header中。但是我不知道$value =~ s/^\s+//;和$value =~ s/\s+$//;之间有什么区别。 $val
我是一名优秀的程序员,十分优秀!