这是一个把记事本中的内容读取到内存中并将内容显示在屏幕上的demo。在这个demo中,整个程序的流程是这样:
step 1:首先在程序的assets文件夹下存放一个test.txt文件,文件是utf-8编码格式,里面存放的是一篇文章。windows下生成的记事本默认是ANSI编码格式,你只需要点击 文件 --> 另存为 --> 在弹出框中把编码格式改成utf-8 --> 保存覆盖原文件即可。
step 2:检测sdcard是否插入,false则输出提示:"sdcard未插入。",true则执行step3。
step 3:检测sdcard中mana文件夹下是否有test.txt文件,如果有则读取文件内容,如果没有则从assets中把test.txt文件拷贝到sdcard的mana文件夹下,然后读取sdcard中的test.txt文件内容。
step 4:把文件内容显示到设备屏幕上大功告成。
显示效果如下:
这个是布局main.xml的内容,只有一个textView,在textView外层包了一个scrollView,使得当文字多于屏幕能够显示的能力时可以拖动文字。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@id/text_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</ScrollView>
</RelativeLayout>
Main.class,这是显示的Activity,其中最关键的是对MappedByteBuffer类的掌握。
/**
* 从SDCard中读取文本内容
* @author haozi
*
*/
public class Main extends Activity {
public static final String SDCARD_FILEDIR_PATH = "sdcard/mana/";
private TextView textContent; // 在这个控件中显示文本信息
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.textContent = (TextView) this.findViewById(R.id.text_content);
String content = getTextContent("test.txt");
this.textContent.setText(content);
}
/**
* 得到文本中的内容
* @param textFilePath 文本文件在assets下的相对路径
* @return
*/
private String getTextContent(String textFilePath){
String content = "";
// 检测SDCard是否插入
if(SDCardUtil.checkSDCARD()){
// 1 获取文件
File tempFile = null;
// 检测文件是否存在
if(SDCardUtil.checkFileExist(SDCARD_FILEDIR_PATH, "test.txt")){// 文件存在,则获取这个文件
// 查找目录下所有后缀名为txt的文件。
File[] files = SDCardUtil.findSDCardFile("sdcard/mana/", "txt");
if(files != null && files.length > 0){
for(int i=0; i<files.length; i++){
if("test.txt".equals(files[i].getName())){
tempFile = files[i];
}
}
}
}else{// 文件不存在,则创造这个文件
tempFile = SDCardUtil.createFile2SDCard(SDCARD_FILEDIR_PATH, "test.txt");
// 从assets中复制文件到sdcard中。
if(AssetsUtil.isAssetExistent(Main.this, textFilePath)){
InputStream is = AssetsUtil.openAssetPostion(Main.this, textFilePath);
try {
FileUtils.copyInputStreamToFile(is, tempFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 2 读取文本到MappedByteBuffer中
// MappedByteBuffer 将文件直接映射到内存(这里的内存指的是虚拟内存,并不是物理内存,后面说证明这一点)。
// 通常,可以映射整个文件,如果文件比较大的话可以分段进行映射,只要指定文件的那个部分就可以。而且,与ByteBuffer十分类似,
// 没有构造函数(你不可new MappedByteBuffer()来构造一个MappedByteBuffer),我们可以通过 java.nio.channels.FileChannel 的 map() 方法来获取 MappedByteBuffer 。
// 其实说的通俗一点就是Map把文件的内容被映像到计算机虚拟内存的一块区域,这样就可以直接操作内存当中的数据而无需操作的时候每次都通过I/O去物理硬盘读取文件,所以效率上有很大的提升!
// FileChannel提供了map方法来把文件影射为内存映像文件: MappedByteBuffer map(int mode,long position,long size);
// 可以把文件的从position开始的size大小的区域映射为内存映像文件,mode指出了 可访问该内存映像文件的方式
MappedByteBuffer buffer = null;
long bufferLength = 0;
try {
RandomAccessFile rFile = new RandomAccessFile(tempFile, "r");
bufferLength = rFile.length();
buffer = rFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, bufferLength);
byte[] bytes = new byte[(int) bufferLength];
for(int i=0; i<bytes.length; i++){
bytes[i] = buffer.get(i);
}
content = new String(bytes, "utf-8");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
content = "sdcard没有插入。";
}
return content;
}
}
两个类工具,负责对sdcard和assets的检测和文件操作。
AssetsUtil
public class AssetsUtil {
/**
* 判断assets下是否存在某文件(判断完后,会关闭IO流)
*
* @param assetPath
* @return
*/
public static boolean isAssetExistent(Context context, String assetPath) {
InputStream is = null;
try {
is = context.getAssets().open(assetPath);
return is != null;
} catch (IOException e) {
return false;
} finally {
try {
if(is != null)
is.close();
} catch (IOException e) {
}
}
}
/**
* 判断assets下是否存在某文件,若存在,直接返回IO流,否则返回空
*
* @param assetPath
* @return
*/
public static InputStream openAssetPostion(Context context, String assetPath) {
InputStream is = null;
try {
is = context.getAssets().open(assetPath);
return is;
} catch (IOException e) {
return null;
}
}
}
SDcardUtil
public class SDCardUtil {
private static String SDPATH;
static {
// 得到当前外部存储设备的目录
// /SDCARD
SDPATH = Environment.getExternalStorageDirectory() + "/";
}
public static String getSDPATH() {
return SDPATH;
}
/**
* 检查SD卡是否插入
*
* @return
*
*/
public static boolean checkSDCARD() {
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED)) {
return true;
}
return false;
}
/**
* 创建文件到SDCard中
*
* @param path
* @param fileName
* @return true:创建成功 false:创建失败(文件已经存在)
*
*/
public static File createFile2SDCard(String path, String fileName) {
// ///////////////////////////////////////
// 创建SD卡目录
// ///////////////////////////////////////
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
// //////////////////////////////////////////
// 创建SD卡文件
// ///////////////////////////////////////////
File file = new File(path + fileName);
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return file;
}
/**
* 判断文件是否存在在SDCard卡上
*
* @param path
* @param fileName
* @return
*/
public static boolean checkFileExist(String path, String fileName) {
File file = new File(path + fileName);
return file.exists();
}
/**
* 查找某目录下所有fileType类型的文件
*
* @param path
* @param fileType
* @return
*
*/
public static File[] findSDCardFile(String path, final String fileType) {
File dir = new File(path);
if (dir.isDirectory()) {
File[] files = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
return (filename.endsWith(fileType));
}
});
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(File str1, File str2) {
return str2.getName().compareTo(str1.getName());
}
});
return files;
}
return null;
}
}
当然,对sdcard的操作要记得在AndroidManifest.xml中添加对sdcard操作文件的权限。
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
在这个demo中,我还使用了阿帕奇提供的common项目的一些好用的工具jar包。它们使我在对文件处理操作上省下了不少代码。