小米开源文件管理器MiCodeFileExplorer-源码研究(4)-文件操作工具类FileOperationHelper

文件操作是非常通用的,注释都写在源代码中了,不多说~
需要特别说明的是,任务的异步执行和IOperationProgressListener。
拷贝和删除等操作,是比较费时的,采用了异步执行的方式~

Android异步执行,我也是初次了解,在CSDN上找了一篇文章,后续写个单独的例子,单独写1篇介绍。
http://blog.csdn.net/xufenghappy6/article/details/7343899
异步执行+事件通知 是一种比较流行的模式,比同步等待很多时候要好。

另外,特别需要说明的是,Java应用程序中、Android、Windows开发、Linux Shell都会有文件File的概念,他们本质是一样的。
文件的核心概念基本一致,都是用的操作系统的文件概念,不同操作系统之间的区别也不大。
创建、删除、重命名、复制、粘贴,输入-执行-输出,也都一样。

package net.micode.fileexplorer.util;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;

import net.micode.fileexplorer.model.FileInfo;
import android.os.AsyncTask;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
/**文件操作工具类,执行文件的创建、移动、粘贴、重命名、删除等*/
public class FileOperationHelper {
	private static final String LOG_TAG = "FileOperation";
    //内部文件集合,用来临时保存复制、移动等操作,用户选择的文件集合
	private ArrayList<FileInfo> mCurFileNameList = new ArrayList<FileInfo>();

	private boolean mMoving;

	private IOperationProgressListener mOperationListener;

	private FilenameFilter mFilter;

	public interface IOperationProgressListener {
		void onFinish();

		void onFileChanged(String path);
	}

	public FileOperationHelper(IOperationProgressListener l) {
		mOperationListener = l;
	}

	public void setFilenameFilter(FilenameFilter f) {
		mFilter = f;
	}

	//根据路径和文件名,创建文件
	public boolean CreateFolder(String path, String name) {
		Log.v(LOG_TAG, "CreateFolder >>> " + path + "," + name);

		File f = new File(Util.makePath(path, name));
		if (f.exists())
			return false;

		return f.mkdir();
	}

	//拷贝若干个文件,把文件集合拷贝到“当前文件集合中mCurFileNameList”,可以供“粘贴操作”使用
	public void Copy(ArrayList<FileInfo> files) {
		copyFileList(files);
	}

	//粘贴,把当前文件集合中“mCurFileNameList”的文件,拷贝到目标路径下
	public boolean Paste(String path) {
		if (mCurFileNameList.size() == 0)
			return false;

		final String _path = path;
		//异步执行某个任务
		asnycExecute(new Runnable() {
			@Override
			public void run() {
				for (FileInfo f : mCurFileNameList) {
					CopyFile(f, _path);
				}
				//通知操作变化
				mOperationListener.onFileChanged(Environment
						.getExternalStorageDirectory().getAbsolutePath());
                //粘贴之后,需要清空mCurFileNameList
				clear();
			}
		});

		return true;
	}

	//是否可以“粘贴”,mCurFileNameList有元素
	public boolean canPaste() {
		return mCurFileNameList.size() != 0;
	}

	//开始移动,标记“正在移动”,拷贝文件集合
	public void StartMove(ArrayList<FileInfo> files) {
		if (mMoving)
			return;

		mMoving = true;
		copyFileList(files);
	}

	//移动状态
	public boolean isMoveState() {
		return mMoving;
	}

	//能否移动,假设path为“C:/a/b”,f.filePath为“C:、/a/b/c/d.png”,不能移动
	//TODO 感觉不太靠谱啊,为啥不能移动到文件的上级目录呢?
	public boolean canMove(String path) {
		for (FileInfo f : mCurFileNameList) {
			if (!f.IsDir)
				continue;

			if (Util.containsPath(f.filePath, path))
				return false;
		}

		return true;
	}

	//清空当前文件集合
	public void clear() {
		synchronized (mCurFileNameList) {
			mCurFileNameList.clear();
		}
	}

	//停止移动,移动文件是异步执行,结束后有事件通知
	public boolean EndMove(String path) {
		if (!mMoving)
			return false;
		mMoving = false;

		if (TextUtils.isEmpty(path))
			return false;

		final String _path = path;
		asnycExecute(new Runnable() {
			@Override
			public void run() {
				for (FileInfo f : mCurFileNameList) {
					MoveFile(f, _path);
				}

				mOperationListener.onFileChanged(Environment
						.getExternalStorageDirectory().getAbsolutePath());

				clear();
			}
		});

		return true;
	}

	public ArrayList<FileInfo> getFileList() {
		return mCurFileNameList;
	}

	//异步执行某个任务
	//android的类AsyncTask对线程间通讯进行了包装,提供了简易的编程方式来使后台线程和UI线程进行通讯:后台线程执行异步任务,并把操作结果通知UI线程。
	//可以参考http://blog.csdn.net/xufenghappy6/article/details/7343899
	private void asnycExecute(Runnable r) {
		final Runnable _r = r;
		new AsyncTask() {
			@Override
			protected Object doInBackground(Object... params) {
				synchronized (mCurFileNameList) {
					_r.run();
				}
				if (mOperationListener != null) {
					mOperationListener.onFinish();
				}

				return null;
			}
		}.execute();
	}

	//某个路径是否被选中
	public boolean isFileSelected(String path) {
		synchronized (mCurFileNameList) {
			for (FileInfo f : mCurFileNameList) {
				if (f.filePath.equalsIgnoreCase(path))
					return true;
			}
		}
		return false;
	}

	//文件重命名
	public boolean Rename(FileInfo f, String newName) {
		if (f == null || newName == null) {
			Log.e(LOG_TAG, "Rename: null parameter");
			return false;
		}

		File file = new File(f.filePath);
		String newPath = Util.makePath(Util.getPathFromFilepath(f.filePath),
				newName);
		final boolean needScan = file.isFile();
		try {
			boolean ret = file.renameTo(new File(newPath));
			if (ret) {
				if (needScan) {
					mOperationListener.onFileChanged(f.filePath);
				}
				mOperationListener.onFileChanged(newPath);
			}
			return ret;
		} catch (SecurityException e) {
			Log.e(LOG_TAG, "Fail to rename file," + e.toString());
		}
		return false;
	}

	//删除若干文件,先copy文件集合,再异步执行删除操作,删除完成后,有通知
	public boolean Delete(ArrayList<FileInfo> files) {
		copyFileList(files);
		asnycExecute(new Runnable() {
			@Override
			public void run() {
				for (FileInfo f : mCurFileNameList) {
					DeleteFile(f);
				}

				mOperationListener.onFileChanged(Environment
						.getExternalStorageDirectory().getAbsolutePath());

				clear();
			}
		});
		return true;
	}

	//删除1个文件
	protected void DeleteFile(FileInfo f) {
		if (f == null) {
			Log.e(LOG_TAG, "DeleteFile: null parameter");
			return;
		}

		File file = new File(f.filePath);
		boolean directory = file.isDirectory();
		if (directory) {
			for (File child : file.listFiles(mFilter)) {
				if (Util.isNormalFile(child.getAbsolutePath())) {
					DeleteFile(Util.GetFileInfo(child, mFilter, true));
				}
			}
		}

		file.delete();

		Log.v(LOG_TAG, "DeleteFile >>> " + f.filePath);
	}

	//执行1个文件的拷贝,如果文件是目录,拷贝整个目录,可能有递归Copy
	private void CopyFile(FileInfo f, String dest) {
		if (f == null || dest == null) {
			Log.e(LOG_TAG, "CopyFile: null parameter");
			return;
		}

		File file = new File(f.filePath);
		if (file.isDirectory()) {

			// directory exists in destination, rename it
			String destPath = Util.makePath(dest, f.fileName);
			File destFile = new File(destPath);
			int i = 1;
			while (destFile.exists()) {
				destPath = Util.makePath(dest, f.fileName + " " + i++);
				destFile = new File(destPath);
			}

			for (File child : file.listFiles(mFilter)) {
				if (!child.isHidden()
						&& Util.isNormalFile(child.getAbsolutePath())) {
					CopyFile(Util.GetFileInfo(child, mFilter, Settings
							.instance().getShowDotAndHiddenFiles()), destPath);
				}
			}
		} else {
			String destFile = Util.copyFile(f.filePath, dest);
		}
		Log.v(LOG_TAG, "CopyFile >>> " + f.filePath + "," + dest);
	}

	//移动文件,通过重命名的方式,移动的
	private boolean MoveFile(FileInfo f, String dest) {
		Log.v(LOG_TAG, "MoveFile >>> " + f.filePath + "," + dest);

		if (f == null || dest == null) {
			Log.e(LOG_TAG, "CopyFile: null parameter");
			return false;
		}

		File file = new File(f.filePath);
		String newPath = Util.makePath(dest, f.fileName);
		try {
			return file.renameTo(new File(newPath));
		} catch (SecurityException e) {
			Log.e(LOG_TAG, "Fail to move file," + e.toString());
		}
		return false;
	}

	//把文件集合copy到mCurFileNameList中,同步~
	private void copyFileList(ArrayList<FileInfo> files) {
		synchronized (mCurFileNameList) {
			mCurFileNameList.clear();
			for (FileInfo f : files) {
				mCurFileNameList.add(f);
			}
		}
	}

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 06:41:18

小米开源文件管理器MiCodeFileExplorer-源码研究(4)-文件操作工具类FileOperationHelper的相关文章

小米开源文件管理器MiCodeFileExplorer初步研究

2011年对着书本Android应用开发揭秘,写了2个月的HelloWorld. 现在想复习并深入,我没有耐心再去一点点地敲代码了. 4年前自己是个学生,实习,现在有工作,只能业余时间研究. 这一点是非常不同的. 我希望通过研究别人的"成熟产品",更好地全面学习. 以目标为导向,具体来说,通过研究别人的一个产品,进而全面掌握,在研究的过程中, 把若干问题都解决了,从而达成"快速进步"的目标. 我们学习Java,学习Android开发,不是为了玩玩而已,也不能紧紧是&

小米开源文件管理器MiCodeFileExplorer-源码研究(1)-2个模型Model

上篇说到,把小米的Java代码整理成了5个包,其中1个是net.micode.fileexplorer.model.这个包就2个模型类,最基本了,FileInfo和FavoriteItem. package net.micode.fileexplorer.model; /** 抽象了一个文件最基本的信息 */ public class FileInfo { // 文件名 public String fileName; // 文件路径 public String filePath; // 文件大小

小米开源文件管理器MiCodeFileExplorer-源码研究(6)-媒体文件MediaFile和文件类型MimeUtils

接着之前的第4篇,本篇的2个类,仍然是工具类.MediaFile,媒体文件,定义了一大堆的常量,真正的有用的方法就几个.isAudioFileType.isVideoFileType之类的. MimeUtils,文件类型工具类,定义了一大堆的   add("application/zip", "zip");   某种扩展格式,对应的mime类型.   通过阅读代码观察到的2点现象,我有2点猜测:现象1.注释是英文的,很溜的那种~2.好多方法没有被本项目使用.  Ct

小米开源文件管理器MiCodeFileExplorer-源码研究(9)-入口分析

AndroidManifest.xml是Android应用程序最重要的配置文件. 入口文件和intent-filter <application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light" android:uiOptions="splitActionBar

小米开源文件管理器MiCodeFileExplorer-源码研究(3)-2个单实例工具类

从本篇开始,讲解net.micode.fileexplorer.util工具包中的类.这个包下的类,功能也比较单一和独立.很多代码的思想和实现,可以用于JavaWeb和Android等多种环境中. 一.单实例活动管理器ActivitiesManager一个单实例的活动管理器,从方法的被调用程度来看,"徒有其名".registerActivity注册活动方法被使用了,而getActivity没有被使用,感觉明显有问题啊~我目前的猜测:大概是查看文件的时候,就会新建立一个活动,并且注册保存

小米开源文件管理器MiCodeFileExplorer-源码研究(3)-使用最多的工具类Util

Util.java,使用最广泛~代码中很多地方,都写了注释说明~基本不需要怎么解释了~ package net.micode.fileexplorer.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.i

Android开源项目 Universal imageloader 源码研究之项目框架

Universal imageloader 的代码并不复杂 重点是缓存,线程池任务 下面都用UML图进行了绘制 基本使用流程就是 初始化配置,设置Options参数,最后Dispaly提交下载 public static void initImageLoader(Context context) { ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context); config.thr

File Manager文件管理应用android源码

这个刚刚在安卓教程网那里看到的,File Manager文件管理应用android源码,这个是File Manager文件管理应用源码,源码filemanager,一个开源的文件管理器完整源码,文件查询速度非常快,功能基础简单,很适合在这个基础上做增量开发,现在还在开发中可以在google play上下载其beta版本. 可能用到的源码片段:http://code.662p.com/list/173_1.html 使用说明: 详细说明:http://android.662p.com/thread

开源中国安卓客户端源码学习(一) 渐变启动界面

开源中国安卓客户端源码学习(一) 准备学习安卓开发, 看到网上有人推荐开源中国安卓客户端的源码, 说里面包含了大部分技术, 于是准备好好研究研究. 特开通此系列博客来记录学习过程. 由于是在学习, 经验不足, 里面肯定有很多不对的地方, 望大家指正. 到这里下载源码包,开发环境为Linux下Eclipse,导入源码后有可能会出现android.webkit.CacheManager找不到的错误, 原因是这个类在4.0以上版本的SDK被删除了, 只要下载4.0版本的SDK使用即可. 由于googl