这是一个把记事本中的内容读取到内存中并将内容显示在屏幕上的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包。它们使我在对文件处理操作上省下了不少代码。