整理一下关于sd卡相关知识点,主要包括sd卡状态监听,sd卡文件搜索,sd卡媒体数据库(系统支持媒体类型)刷新模块:
一:sd卡状态进行监听
有时程序进行外部数据读取和写入时,为防止异常发生需要对sd卡状态进行监听,对于sd卡的状态我们可以采用注册广播来实现
下面是文档中一个经典例子;
//监听sdcard状态广播 BroadcastReceiver mExternalStorageReceiver; //sdcard可用状态 boolean mExternalStorageAvailable = false; //sdcard可写状态 boolean mExternalStorageWriteable = false; void updateExternalStorageState() { //获取sdcard卡状态 String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { mExternalStorageAvailable = mExternalStorageWriteable = true; } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { mExternalStorageAvailable = true; mExternalStorageWriteable = false; } else { mExternalStorageAvailable = mExternalStorageWriteable = false; } } //开始监听 void startWatchingExternalStorage() { mExternalStorageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.i("test", "Storage: " + intent.getData()); updateExternalStorageState(); } }; IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_MOUNTED); filter.addAction(Intent.ACTION_MEDIA_REMOVED); registerReceiver(mExternalStorageReceiver, filter); updateExternalStorageState(); } //停止监听 void stopWatchingExternalStorage() { unregisterReceiver(mExternalStorageReceiver); }
二:sdcard下搜索某一类型(通常是后缀名相同)文件,或是指定文件名的查找功能
(1)搜索指定文件
public String searchFile(String filename){ String res=""; File[] files=new File("/sdcard").listFiles(); for(File f:files){ if(f.isDirectory()) searchFile(f.getName()); else if(f.getName().indexOf(filename)>=0) res+=f.getPath()+"\n"; } if(res.equals("")) res="file can't find!"; return res; }
(2)指定相同后缀名称文件类型
private List<String> files = new ArrayList<String>(); class FindFilter implements FilenameFilter { public boolean accept(File dir, String name) { return (name.endsWith(".txt")); } } public void updateList() { File home = new File("/sdcard/"); if (home.listFiles( new FindFilter()).length > 0) { for (File file : home.listFiles( new FindFilter())) { files.add(file.getName()); }
三:媒体数据库的刷新,
当android的系统启动的时候,系统会自动扫描sdcard内的文件,并把获得的媒体文件信息保存在一个系统媒体数据库中,
程序想要访问多媒体文件,就可以直接访问媒体数据库中即可,而用直接去sdcard中取。
但是,如果系统在不重新启动情况下,媒体数据库信息是不会更新的,这里举个例子,当应用程序保存一张图片到本地后(已成功),
但打开系统图片库查看时候,你会发现图片库内并没有你刚刚保存的那张图片,原因就在于系统媒体库没有及时更新,这时就需要手动刷新文件系统了
方式一:发送一广播信息通知系统进行文件刷新
private void scanSdCard(){ IntentFilter intentfilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED); intentfilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED); intentfilter.addDataScheme("file"); registerReceiver(scanSdReceiver, intentfilter); Intent intent = new Intent(); intent.setAction(Intent.ACTION_MEDIA_MOUNTED); intent.setData(Uri.parse("file://" + Environment.getExternalStorageDirectory().getAbsolutePath())); sendBroadcast(intent); } private BroadcastReceiver scanSdReceiver = new BroadcastReceiver(){ private AlertDialog.Builder builder; private AlertDialog ad; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if(Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)){ builder = new AlertDialog.Builder(context); builder.setMessage("正在扫描sdcard..."); ad = builder.create(); ad.show(); // adapter.notifyDataSetChanged(); }else if(Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)){ ad.cancel();//重新获取文件数据信息 Toast.makeText(context, "扫描完毕", Toast.LENGTH_SHORT).show(); } } };
或者
public void fileScan(File file){ Uri data = Uri.parse("file://"+ Environment.getExternalStorageDirectory()) sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data)); } void insertMeadia(ContentValues values){ Uri uri = getContentResolver().insert( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri)); }
刷新所有系统文件,效率可能不高,高效方法是只刷新变化的文件
方式二:指定特定文件操作
File path = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File file = new File(path, "DemoPicture.jpg"); try { InputStream is = getResources().openRawResource(R.drawable.balloons); OutputStream os = new FileOutputStream(file); byte[] data = new byte[is.available()]; is.read(data); os.write(data); is.close(); os.close(); // Tell the media scanner about the new file so that it is // immediately available to the user. MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { Log.i("ExternalStorage", "Scanned " + path + ":"); Log.i("ExternalStorage", "-> uri=" + uri); } }); } catch (IOException e) { // Unable to create file, likely because external storage is // not currently mounted. Log.w("ExternalStorage", "Error writing " + file, e); }
文件大小,字符串展示:
public static String getReadableFileSize(int size) { final int BYTES_IN_KILOBYTES = 1024; final DecimalFormat dec = new DecimalFormat("###.#"); final String KILOBYTES = " KB"; final String MEGABYTES = " MB"; final String GIGABYTES = " GB"; float fileSize = 0; String suffix = KILOBYTES; if (size > BYTES_IN_KILOBYTES) { fileSize = size / BYTES_IN_KILOBYTES; if (fileSize > BYTES_IN_KILOBYTES) { fileSize = fileSize / BYTES_IN_KILOBYTES; if (fileSize > BYTES_IN_KILOBYTES) { fileSize = fileSize / BYTES_IN_KILOBYTES; suffix = GIGABYTES; } else { suffix = MEGABYTES; } } } return String.valueOf(dec.format(fileSize) + suffix); }
获取多个sdcard:
fun getSdcardList(): List<File> { val sdFile = File("/storage/")//or /mnt/ // val result = ArrayList<File>() // val sdFile = Environment.getExternalStorageDirectory() val files = sdFile.listFiles() val result = files.toList() return result }