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

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

废话不多说。

首先来看一下DiskLruCache。

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

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

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

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

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

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

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

	static final String JOURNAL_FILE = "journal";
static final String JOURNAL_FILE_TEMP = "journal.tmp";
static final String JOURNAL_FILE_BACKUP = "journal.bkp";
static final String MAGIC = "libcore.io.DiskLruCache";
static final String VERSION_1 = "1";
static final long ANY_SEQUENCE_NUMBER = -1;
static final Pattern LEGAL_KEY_PATTERN = Pattern.compile("[a-z0-9_-]{1,64}");
private static final String CLEAN = "CLEAN";
private static final String DIRTY = "DIRTY";
private static final String REMOVE = "REMOVE";
private static final String READ = "READ";
private final File directory;
private final File journalFile;
private final File journalFileTmp;
private final File journalFileBackup;
private final int appVersion;
private long maxSize;
private int maxFileCount;
private final int valueCount;
private long size = 0;
private int fileCount = 0;
private Writer journalWriter;
private final LinkedHashMap<String, Entry> lruEntries =
new LinkedHashMap<String, Entry>(0, 0.75f, true);
private int redundantOpCount;
private long nextSequenceNumber = 0;
final ThreadPoolExecutor executorService =
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、

public synchronized Snapshot get(String key) throws IOException

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

6、

public synchronized boolean remove(String key) throws IOException

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

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

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

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

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

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

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

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

protected DiskLruCache cache;

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

1、

@Override
public File getDirectory() {
return cache.getDirectory();
}

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

2、

public File get(String imageUri) {
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = cache.get(getKey(imageUri));
return snapshot == null ? null : snapshot.getFile(0);
} catch (IOException e) {
L.e(e);
return null;
} finally {
if (snapshot != null) {
snapshot.close();
}
}
}

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

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

3、

public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {
DiskLruCache.Editor editor = cache.edit(getKey(imageUri));
if (editor == null) {
return false;
} OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);
boolean copied = false;
try {
copied = IoUtils.copyStream(imageStream, os, listener, bufferSize);
} finally {
IoUtils.closeSilently(os);
if (copied) {
editor.commit();
} else {
editor.abort();
}
}
return copied;
}

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

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

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

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

public String readLine() throws IOException {
synchronized (in) {
if (buf == null) {
throw new IOException("LineReader is closed");
}
if (pos >= end) {
fillBuf();
}
for (int i = pos; i != end; ++i) {
if (buf[i] == LF) {
int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
String res = new String(buf, pos, lineEnd - pos, charset.name());
pos = i + 1;
return res;
}
}
ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {
@Override
public String toString() {
int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;
try {
return new String(buf, 0, length, charset.name());
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // Since we control the charset this will never happen.
}
}
}; while (true) {
out.write(buf, pos, end - pos);
// Mark unterminated line in case fillBuf throws EOFException or IOException.
end = -1;
fillBuf();
for (int i = pos; i != end; ++i) {
if (buf[i] == LF) {
if (i != pos) {
out.write(buf, pos, i - pos);
}
pos = i + 1;
return out.toString();
}
}
}
}
}

在最后一个类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. java 不同意同一账户不同IP 同一时候登录系统解决的方法 兼容IE Firefox

    需求就是 不同意同一个账户同一时间登录系统.仅仅要有一个账户在线其它人就是不能用这个账户. 功能非常easy,过程非常纠结 . 这篇文章攻克了兼容IE.Firefox 浏览器下,不同IP 地址 同一用 ...

  2. SQLite中不支持的sql语法

    今天很自然的在写Sql语句的时候用了Top,一开始没发现问题,因为我从数据库读出的值正好是0,而我习惯变量定义的时候也都赋值0,可是到我不要0的时候我就发现问题了.后来才知道,可爱的小sqlite竟然 ...

  3. 大数据笔记10:大数据之Hadoop的MapReduce的原理

    1. MapReduce(并行处理的框架) 思想:分而治之,一个大任务分解成多个小的子任务(map),并行执行后,合并结果(Reduce) (1)大任务分解成多个小任务,这个过程就是map: (2)多 ...

  4. .net打包/c#winfrom程序打包

    1:新建安装部署项目 打开VS,点击新建项目,选择:其他项目类型->安装与部署->安装向导(安装项目也一样),然后点击确定.(详细见下图) 此主题相关图片如下: 2:安装向导 关闭后打开安 ...

  5. textarea固定大小,不可拖动

    写前端,经常很多小东西容易忽略忘记,今天写页面碰到设定一个输入框大小,死活记不起怎么固定,故找了一下度娘,其实添加一个css属性就好了: resize: none; 随笔记一下!

  6. Set,Map数据结构

    /*Set : 多个value的集合, value不重复Map : 多个key-value对的集合, key不重复 1. Set容器 1). Set() 2). Set(array) 3). add( ...

  7. Linq 学习(1) 概述

    本篇简单回顾C#语言集合操作的变化,通过与Linq对等的面向对象的语法来认识Linq.Linq是Language Integrated Query, 初识Linq感觉跟SQL Server的Tsql很 ...

  8. c++回调实现

    回调是A将一个函数指针传给B,然后调用B,B在执行自身函数后,再在合适的时候执行A的这个函数指针,这样就能避免A和B的相互包含和链接,在大型项目中回调是一种打破循环依赖的常用技术. typedef v ...

  9. [Leetcode][015] 3Sum (Java)

    题目在这里: https://leetcode.com/problems/3sum/ [标签] Array; Two Pointers [个人分析] 老实交待,这个题卡半天,第一次做不会,抄别人的.过 ...

  10. WinFrm访问MVC数据

    WinFrm使用HttpWebRequest访问MVC中的Controller,以注册为例,客户端输入注册码后点击注册. WinFrm注册代码:代码中使用的是Post提交,UTF8编码方式. priv ...