Android文件管理--请叫我王优秀

一,实现的功能

  • 1.实现android各个版本看可以任意访问内置存储卡,自定义文件样式并且列表里面展示。
  • 2.实现对文件的剪切,复制,删除,移动。
  • 3.实现对文件目录的排序(日期,大小,名称)
  • 4.实现创建不同类型的文件,例如wold,excle,xml等文件。

如下图所示:实现效果
image

image


二,开始代码

- 自定义炫酷Activity窗口,并且用ListView或者RecylerView来展示我们所要访问的文件夹路径下的所有文件。

遇到的问题解决:

  • 对于手机存储卡的选择。存放位置的选择(内置存储卡,外置SD卡),这个我们可以通过反射来获取内存卡管理者的StorageVolume这样就可以遍历每一个数组,通过isRemoveBle来判断是否可以移除(能移除的当然是有外置存储卡了)。近两年手机都是内置卡,什么16,32,64,128G真的搞个100G以上的你要干啥,而且很多时候手机都没有外置存储卡,这里舍弃了老人机了,我姥爷用的老人机就不提了。所以对于开发者来说,我都会果断选择内置存储卡,存放自己项目中的文件。

下面开始兴建一个项目MyFileManager

  • 手机:手机三星s8
  • 版本:Android8.0.0
  • 手机:三星Note4
  • 版本:6.1.0

拿到外置存储卡: Environment.getExternalStorageDirectory().absolutePath
Environment.getExternalStorageDirectory().absolutePath可以拿到存储卡的,如果有外置sd卡就拿到外置sd卡,如果没有就会内置sd卡,由于我手机都是内置。
当然这里我们可以判断是否具有外置存储卡。这一两年内好多手机都没了外置卡吧,我记得我老爷手机有外置卡槽。这里通过反射我们可以判断是否具有外置卡。代码如下:

   /**
     * 反射调用获取内置存储和外置sd卡根路径
     * @param mContext    上下文
     * @param haveSdCard 是否有卡槽外置卡,false返回内部存储,true返回外置sd卡
     * @return
     */
    private fun getStoragePath(mContext: Context, haveSdCard: Boolean): String? {

        val mStorageManager = mContext.getSystemService(Context.STORAGE_SERVICE) as StorageManager
        var storageVolumeClazz: Class<*>? = null
        try {
            storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
            val getVolumeList = mStorageManager.javaClass.getMethod("getVolumeList")
            val getPath = storageVolumeClazz!!.getMethod("getPath")
            val isRemovable = storageVolumeClazz.getMethod("isRemovable")
            val result = getVolumeList.invoke(mStorageManager)
            val length = Array.getLength(result)
            for (i in 0 until length) {
                val storageVolumeElement = Array.get(result, i)
                val path = getPath.invoke(storageVolumeElement) as String
                val removable = isRemovable.invoke(storageVolumeElement) as Boolean
                Log.e("isRemove",removable.toString())

                if (haveSdCard == removable) {
                    return path
                }
            }
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        } catch (e: InvocationTargetException) {
            e.printStackTrace()
        } catch (e: NoSuchMethodException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        }

        return null
    }

有了路径我们可以获取这个根路径下面所有的文件信息,我想android开发的你也也用过的。

         /**
         * 通过传入的路径,返回该路径下的所有的文件和文件夹列表
         *
         * @param path
         * @return
         */
        fun getListData(path: String): List<FileInfo> {

            val list = ArrayList<FileInfo>()//用来存储便利之后每一个文件中的信息
            val pfile = File(path)// 兴建实例化文件对象
            var files: Array<File>? = null// 声明了一个文件对象数组
            if (pfile.exists()) {// 判断路径是否存在
                files = pfile.listFiles()// 该文件对象下所属的所有文件和文件夹列表
            }else{//如果没有这个文件目录。那么这里去创建
                pfile.mkdirs()
                Log.e("name",pfile.absolutePath)
                files=pfile.listFiles()
            }

            if (files != null && files.size > 0) {// 非空验证
                for (file in files) {//循环遍历然后给适配器所要展示的数据赋值。
                    val item = FileInfo()
                    if (file.isHidden) {
                        continue// 跳过隐藏文件
                    }
                    if (file.isDirectory// 文件夹
                            && file.canRead()//是否可读
                    ) {
                        file.isHidden//  是否是隐藏文件
                        // 获取文件夹目录结构
                        item.icon = R.drawable.folder//图标
                        item.bytesize = file.length()
                        item.size = getSize(item.bytesize.toFloat())//大小
                        item.type = MainActivity.T_DIR

                    } else if (file.isFile) {// 文件
                        Log.i("spl", file.name)
                        val ext = getFileEXT(file.name)
                        Log.i("spl", "ext=$ext")

                        // 文件的图标
                        item.icon = getDrawableIcon(ext)// 根据扩展名获取图标
                        // 文件的大小
                        val size = getSize(file.length().toFloat())
                        item.size = size
                        item.type = MainActivity.T_FILE

                    } else {// 其它
                        item.icon = R.drawable.mul_file
                    }
                    item.name = file.name// 名称
                    item.lastModify = file.lastModified()
                    item.path = file.path// 路径
                    // 最后修改时间
                    val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm")
                    val date = Date(file.lastModified())
                    val time = sdf.format(date)
                    item.time = time
                    list.add(item)
                }
            }
            files = null
            return list
        }

这里我们获取路径:

外置卡的路径

image

如上图可以获取所有的路径和信息我们接下来将所有的这些路径来用一个ListView展示。

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //1.动态权限的获取。
        checkPermission()
        //2.获取文件列表数据
        list = FileUtils.getListData(getStoragePath(this, false)!!)// 数据
        iniView()
     }

    private fun iniView() {
        mAdapter= FileAdapter(this)
        mAdapter.list=list
        mAdapter.setProxy(this)
        list_file.adapter=mAdapter
        mAdapter.notifyDataSetChanged()

    }

如下图所示:

image


- 2.实现对文件的剪切,复制,删除,移动。

在Adapter里面我们定义一个HashMap用来存储我们选择的item的position,然后item点击事件我们可以通过操作和比较这个hashMap里面的个数来决定下面布局是否显示,当我们点击下面取消时候,我们清除适配器里面的hashMap,然后跟新我们的适配器达到列表的更新和最下面布局的是否消失或者显示。代码如下:


  • > 取消所有选择功能:其实就是将适配器里面存储选中item的集合里面的选中标全部修改为未选中,然后刷新适配器就可以看到效果了。
   //点击Item时候,选择item然后再次点击取消,如果slectMap中没有存储的key那么就可以影藏下面的布局文件。
       override fun itemClick(position: Int) {
        //点击多选的实现
        if (mAdapter.selectMap.containsKey(position)) {
            //删除key
            mAdapter.selectMap.remove(position)
            if (mAdapter.selectMap.size === 0) {

                bottom.setVisibility(View.GONE)
            } else {
                bottom.setVisibility(View.VISIBLE)
            }
        } else {

            bottom.setVisibility(View.VISIBLE)
            mAdapter.selectMap.put(position, position)
        }
        mAdapter.notifyDataSetChanged()
    }

    //全不选操作
    fun selectNone(v: View) {
        mAdapter.selectMap.clear()

        mAdapter.notifyDataSetChanged()
    }

image

  • 复制功能:我们定义一个HashMap用来存储我们选中item的positon所对应的路径,然后这时候我们激活粘贴,去操作这个hashMap和当前路径结合来创建文件或者路径,同事更新list数据刷新适配器。
   //复制
    fun cope(view: View) {

        if (mAdapter.selectMap.size === 0) {
            Toast.makeText(this, "您还没选中任何项目!", Toast.LENGTH_SHORT).show()
        } else {

            //把用户信息保存到一个合理的数据结构中等待粘贴时候遍历兴建
            copyMap.clear()
            for (position in mAdapter.selectMap.keys) {

                copyMap[position] = list[position!!].path
            }
            Toast.makeText(this, copyMap.size.toString() + "个项目已保存", Toast.LENGTH_SHORT).show()
            //切换粘贴为激活状态
            //切换粘贴为激活状态
            layout.isEnabled = true

            img.setImageResource(R.drawable.ic_menu_paste_holo_light)

        }

    }
  • 剪切功能:我们同样用定义的HashMap用来存储我们选中item的positon所对应的路径,然后这时候我们激活粘贴,去操作这个hashMap和当前路径结合来创建文件或者路径,删除之前选中的路径,同事更新list数据刷新适配器。
  //剪切
    public void pathDelete(View v) {
        if (adapter.selectMap.size() > 0) {
            copyMap.clear();
            for (Integer position : adapter.selectMap.keySet()) {

                copyMap.put(position, list.get(position).path);
            }


            for (String path : copyMap.values()) {
                File file = new File(path);
                if (file.isFile()) {
                    int res = Utils.pasteFile(currPath, new File(path));
                    isCut=true;
                    //切换粘贴为激活状态
                    layout.setEnabled(true);
                    img.setImageResource(R.drawable.ic_menu_paste_holo_light);
                    Toast.makeText(this, path + "文件剪切成功", Toast.LENGTH_SHORT).show();

                }

                if (file.isDirectory()) {

                    Utils.pasteDir(currPath, new File(path));
                }
            }

        } else {

            Toast.makeText(this, "没有可粘帖的项目", Toast.LENGTH_SHORT).show();
        }

    }

  • 删除功能:我们同样用定义的HashMap用来存储我们选中item的positon所对应的路径,然后这时候我们激活粘贴,去操作这个hashMap和当前路径结合来创建文件或者路径,删除之前选中的路径,同事更新list数据刷新适配器。
fun delete(view: View) {

        if (mAdapter.selectMap.size === 0) {
            Toast.makeText(this, "您还没选中任何项目!", Toast.LENGTH_SHORT).show()

        } else {


            //显示确认框
            AlertDialog.Builder(this)
                    .setTitle("系统提示")
                    .setMessage("您是否要删除这" + mAdapter.selectMap.size + "个项目")
                    .setPositiveButton("确定") { dialog, which ->
                        //遍历
                        for (position in mAdapter.selectMap.keys) {
                            val path = list[position!!].path
                            val file = File(path)
                            //根据path路径删除文件
                            if (file.isFile()) {
                                FileUtils.deleteFile(path)
                            }
                            if (file.isDirectory()) {
                                FileUtils.deleteDir(path)
                            }

                        }
                        //更新
                        mAdapter.selectMap.clear()
                        updateData(currPath)
                    }
                    .setNegativeButton("取消", null)
                    .create().show()
        }
    }

如下图所示:

image

image

https://github.com/luhenchang/MyFileManager.git不知道是不是这一个。你们试一试找了好久

发布了47 篇原创文章 · 获赞 54 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/m0_37667770/article/details/82745977
今日推荐