相对于第一篇来讲,这里讲的是磁盘缓存的延续。在这里我们主要是关注四个类。各自是DiskLruCache、LruDiskCache、StrictLineReader以及工具类Util。

接下来逐一的对它们进行剖析。

废话不多说。

首先来看一下DiskLruCache。

这个类的主要功能是什么呢?我们先来看一段类的凝视:

  1. /**
  2. * A cache that uses a bounded amount of space on a filesystem. Each cache
  3. * entry has a string key and a fixed number of values. Each key must match
  4. * the regex <strong>[a-z0-9_-]{1,64}</strong>. Values are byte sequences,
  5. * accessible as streams or files. Each value must be between {@code 0} and
  6. * {@code Integer.MAX_VALUE} bytes in length.
  7. * <p>This class is tolerant of some I/O errors. If files are missing from the
  8. * filesystem, the corresponding entries will be dropped from the cache. If
  9. * an error occurs while writing a cache value, the edit will fail silently.
  10. * Callers should handle other problems by catching {@code IOException} and
  11. * responding appropriately.
  12. */

对英文不感兴趣的童鞋别急,以下略微翻译一下:

这是基于文件系统所构建的一个基于有限空间的缓存。每个缓存入口都有一个字符串秘钥与固定的数字的序列。每个秘钥一定要与正則表達式<strong>[a-z0-9_-]{1,64}</strong>进行匹配。数值则是一些字节序列,是能够作为流或者文件被訪问的。每个数值在长度上一定是在0与最大的整数之间的。这个缓存类对部分的I/O操作室容忍的。假设有一些文件从文件系统中丢失,对应的缓存的入口ᐟ会从缓存中移除。

假设在写入一个缓存的数值的时候发生了以外的错误,

当前的编辑也会默默的撤销,回调者则会通过捕获一些I/O异常与核实的回应来处理一些其它的问题。

因为DiskLruCache的代码量较多,我们还是从一些核心的变量与方法上来讲述它。核心变量例如以下:

  1. static final String JOURNAL_FILE = "journal";
  2. static final String JOURNAL_FILE_TEMP = "journal.tmp";
  3. static final String JOURNAL_FILE_BACKUP = "journal.bkp";
  4. static final String MAGIC = "libcore.io.DiskLruCache";
  5. static final String VERSION_1 = "1";
  6. static final long ANY_SEQUENCE_NUMBER = -1;
  7. static final Pattern LEGAL_KEY_PATTERN = Pattern.compile("[a-z0-9_-]{1,64}");
  8. private static final String CLEAN = "CLEAN";
  9. private static final String DIRTY = "DIRTY";
  10. private static final String REMOVE = "REMOVE";
  11. private static final String READ = "READ";
  12. private final File directory;
  13. private final File journalFile;
  14. private final File journalFileTmp;
  15. private final File journalFileBackup;
  16. private final int appVersion;
  17. private long maxSize;
  18. private int maxFileCount;
  19. private final int valueCount;
  20. private long size = 0;
  21. private int fileCount = 0;
  22. private Writer journalWriter;
  23. private final LinkedHashMap<String, Entry> lruEntries =
  24. new LinkedHashMap<String, Entry>(0, 0.75f, true);
  25. private int redundantOpCount;
  26. private long nextSequenceNumber = 0;
  27. final ThreadPoolExecutor executorService =
  28. new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

上面的变量大致进行归类。包含:日志文件的命名。日志文件的開始5行内容的变量的定义,文件尺寸与数量的限制以及一个LinkedHashMap来维持一个缓存队列,最后另一个线程池。

接下来大致介绍一下里面的函数的功能:

1、readJournal  这个函数的功能是1、计算当前的日志的缓存的行数、2、计算当前的缓存的日志文件里冗余的行数  3、读取而且处理缓存的日志中的每一行的数据

2、readJournalLine 这个函数的功能是真正的运行每一行日志的操作   当在日志中遇到一个keyword的时候,从当前的缓存的度列中查看当前的keyword所映射的对象是否存在,假设不存在。以当前的keyword创建一个新的对象而且放到当前的缓存的队列中。

3、processJournal  计算初始化的尺寸,而且回收缓存中的一些垃圾。脏的入口将会被觉得是前后矛盾的,将会被回收。

4、rebuildJournal 这个函数的功能是创建一个新的删除大量冗余信息的日志文件,假设当前的日志文件存在。将会替换掉当前的日志文件。

5、

  1. public synchronized Snapshot get(String key) throws IOException

这个函数的功能是返回一个命名为key的文件入口的快照。而且假设当前的数值是返回的,那么它将会被移动到LRU队列的头部。

6、

  1. public synchronized boolean remove(String key) throws IOException

假设当前的文件实体是存在的而且是可以删除的。那么就删除当前的文件的实体。当前正在被编辑的文件实体是不可以被删除的。

接下来关注一下这个类中的三个比較重要的内部类,各自是Snapshot、Editor与Entry。

大致介绍一些这三个类的功能。

Snapshot是缓存的文件实体的数值的一个快照。Editor是编辑缓存的文件实体的数值。

Entry是缓存的文件实体的数据模型。

接下来我们分下一下LruDiskCache这个类的主要功能。

正如这个类的名称一样,这是一个近期最久未使用的磁盘缓存。这样这个类的大致的功能我们清楚了。

我们会在这个类中看到这样一个成员变量

  1. protected DiskLruCache cache;

由此可见当前的类,是DiskLruCache针对磁盘缓存的接口的一个适配器。不信?我们从以下的方法中能够看出:

1、

  1. @Override
  2. public File getDirectory() {
  3. return cache.getDirectory();
  4. }

获取当前的缓存的文件夹。

2、

  1. public File get(String imageUri) {
  2. DiskLruCache.Snapshot snapshot = null;
  3. try {
  4. snapshot = cache.get(getKey(imageUri));
  5. return snapshot == null ? null : snapshot.getFile(0);
  6. } catch (IOException e) {
  7. L.e(e);
  8. return null;
  9. } finally {
  10. if (snapshot != null) {
  11. snapshot.close();
  12. }
  13. }
  14. }

通过图片的uri的对象获取图片文件的句柄。

是通过DiskLruCache中的快照实现的。

3、

  1. public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {
  2. DiskLruCache.Editor editor = cache.edit(getKey(imageUri));
  3. if (editor == null) {
  4. return false;
  5. }
  6.  
  7. OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);
  8. boolean copied = false;
  9. try {
  10. copied = IoUtils.copyStream(imageStream, os, listener, bufferSize);
  11. } finally {
  12. IoUtils.closeSilently(os);
  13. if (copied) {
  14. editor.commit();
  15. } else {
  16. editor.abort();
  17. }
  18. }
  19. return copied;
  20. }

利用的是DiskLruCache中的文件编辑类Editor来讲当前的文件输入流写到生成的文件里。

其余的函数也是以此类推。

接下来要讲的类StrictLineReader。我们也是可将将其理解为一个帮助类,它是专门为读取缓存日志的内容而特别设计的。

主要观察以下的一个方法:

  1. public String readLine() throws IOException {
  2. synchronized (in) {
  3. if (buf == null) {
  4. throw new IOException("LineReader is closed");
  5. }
  6. if (pos >= end) {
  7. fillBuf();
  8. }
  9. for (int i = pos; i != end; ++i) {
  10. if (buf[i] == LF) {
  11. int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
  12. String res = new String(buf, pos, lineEnd - pos, charset.name());
  13. pos = i + 1;
  14. return res;
  15. }
  16. }
  17. ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {
  18. @Override
  19. public String toString() {
  20. int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;
  21. try {
  22. return new String(buf, 0, length, charset.name());
  23. } catch (UnsupportedEncodingException e) {
  24. throw new AssertionError(e); // Since we control the charset this will never happen.
  25. }
  26. }
  27. };
  28.  
  29. while (true) {
  30. out.write(buf, pos, end - pos);
  31. // Mark unterminated line in case fillBuf throws EOFException or IOException.
  32. end = -1;
  33. fillBuf();
  34. for (int i = pos; i != end; ++i) {
  35. if (buf[i] == LF) {
  36. if (i != pos) {
  37. out.write(buf, pos, i - pos);
  38. }
  39. pos = i + 1;
  40. return out.toString();
  41. }
  42. }
  43. }
  44. }
  45. }

在最后一个类Util中,主要是封装了三个方法。

1、readFully  从Reader中读取内容。而且拼接成为一个完整的字符串

2、deleteContents 迭代删除文件的文件夹的内容

3、closeQuietly 静默关闭文件流

Ok,关于磁盘存储的扩展就说到这里。希望对各位童鞋有所帮助。

具体解说Android的图片下载框架UniversialImageLoader之磁盘缓存的扩展(二)的更多相关文章

  1. 具体解说Android的图片下载框架UniversialImageLoader之磁盘缓存(一)

    沉浸在Android的开发世界中有一些年头的猴子们,预计都可以深深的体会到Android中的图片下载.展示.缓存一直是心中抹不去的痛.鄙人亦是如此.Ok,闲话不说.为了督促自己的学习.以下就逐一的挖掘 ...

  2. 具体解说Android图片下载框架UniversialImageLoader之内存缓存(三)

    前面的两篇文章着重介绍的是磁盘缓存,这篇文章主要是解说一下内存缓存.对于内存缓存.也打算分两篇文章来进行解说.在这一篇文章中,我们主要是关注三个类, MemoryCache.BaseMemoryCac ...

  3. AJ学IOS(55)多线程网络之图片下载框架之SDWebImage

    AJ分享,必须精品 效果: 代码: - (NSArray *)apps { if (!_apps) { NSArray *dictArray = [NSArray arrayWithContentsO ...

  4. Android实现图片下载并保存SD卡

    一.首先获取图片 //第一种获取图片的方法 String filePath = downloadUrl; //以下是取得图片的方法 取得的是InputStream,直接从InputStream生成bi ...

  5. Android自定义“图片+文字”控件四种实现方法之 二--------个人最推荐的一种

    http://blog.csdn.net/yanzi1225627/article/details/8633872 第二种方法也要新建一个图片+文字的xml布局文件,然后写一个类继承自LinearLa ...

  6. 关于Exceptionless日志收集框架如何关闭磁盘缓存

    问题:在使用Exceptionless的时候,Exception在收集到日志时会默认在appdata里面缓存当条日志的缓存文件,时间久了之后,如果收集到的日志越多磁盘的空间就会不足. 我使用的环境是 ...

  7. 【转】Picasso – Android系统的图片下载和缓存类库

    来源:http://blog.chengyunfeng.com/?p=492 另一篇参考:http://blog.csdn.net/xu_fu/article/details/17043231 Pic ...

  8. Picasso – Android系统的图片下载和缓存类库

    Picasso – Android系统的图片下载和缓存类库 Picasso 是Square开源的一个用于Android系统下载和缓存图片的项目.该项目和其他一些下载图片项目的主要区别之一是:使用4.0 ...

  9. Android常用优秀开源框架

    Android常用优秀开源框架 https://github.com/Ericsongyl/AOSF AOSF:全称为Android Open Source Framework,即Android优秀开 ...

随机推荐

  1. 四、Solr数据源配置(JNDI、DIH)及定时重做索引

    简介 Solr支持很多种创建索引的方式,包括网页,xml以及数据库,因为我这边做的是企业级的搜索,所以用的是数据库建立索引.其实从数据库建立索引,很大程度上取决于原来的数据库设计. 从数据库建立索引, ...

  2. C++ Win32控制台应用程序捕捉关闭事件

      #include#includebool ctrlhandler( DWORD fdwctrltype ){    switch( fdwctrltype )    {    // handle ...

  3. passwd-shadow文件

    [root@rusky /]# vi /etc/passwd root:x:::Redhat5:/root:/bin/bash rusky:x::::/home/rusky:/bin/bash 1.r ...

  4. mybatis 与 反射

    Mybatis是个优秀的ORM框架,所以它的反射层一定不会让我们失望 图比较大,可以开新页面查看 可以看到,Mybatis对这一块抽象的比较复杂,我们可以看到有几个比较主要的部分:Reflector. ...

  5. js精度丢失解决办法

    /** * 加法运算,避免数据相加小数点后产生多位数和计算精度损失. * * @param num1加数1 | num2加数2 */ function numAdd(num1, num2) { var ...

  6. JS客户端读取Excel文件插件js-xls使用方法

    js-xls是一款客户端读取Excel的插件,亲测IE11.FireFox.Chrome可用,读取速度也客观. 插件Demo地址:http://oss.sheetjs.com/js-xlsx/    ...

  7. The type or namespace name 'Script' does not exist in the namespace 'System.Web' (are you missing an assembly reference?)

    应该说是 .net4 的bug,没有所谓的 System.Web.Extensions.dll 库文件,需要将项目的 Target Framework修改为 3.5版本,才能加载System.Web. ...

  8. JCo 指南

    http://blog.csdn.net/asdfak/article/details/5834731 JAVA 调用SAP端接口 Java Connector and BAPI 前些日子想去深入的研 ...

  9. Popular Cows (POJ No.2186)

    Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= ...

  10. Cocos2DX新手入门笔记索引

    01--从根源种子CCNode说起 02—从Cocos2DX视角看游戏组成 03--理解HelloWorld结构 04--简单菜单使用 05--简单场景切换与精灵创建 06--触摸事件响应 07--动 ...