相对于第一篇来讲,这里讲的是磁盘缓存的延续。在这里我们主要是关注四个类。各自是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. Android开发编码规范(自用)

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持!   Android开发编码规范 目的及指导原则 目的 统一规范 Eclipse编辑环境 ...

  2. Lambda 笔记

    lambda表达式,将会带来代码的灵活性,同时使我们的代码更具表现力. Dim doubleIt As Func(Of Integer, Integer) = _ Function(x As Inte ...

  3. java开发的web下载大数据时的异常处理

    同事用java开发了一个系统,其中有一个功能是下载大约10万笔数据到Excel中.当上线后,很多用户反映下载数据量大的时候就不能成功,但有时可以,所以结论就是系统不稳定,这个问题拖了很久没有解决. 在 ...

  4. 第一个Delphi小程序

    第一次应工作需呀,接触这个语言,今晚在自己的电脑搭建好环境,写的第一个超简单的Delphi小程序! var temp:Integer; //求个位数 procedure TForm1.BitBtn1C ...

  5. C#高级知识点概要(2) - 线程并发锁

    本文目录: 线程的简单使用 并发和异步的区别 并发控制 - 锁 线程的信号机制 线程池中的线程 案例:支持并发的异步日志组件 线程的简单使用 常见的并发和异步大多是基于线程来实现的,所以本文先讲线程的 ...

  6. angularjs中ng-switch的用法

    <!DOCTYPE html> <html lang="zh-CN" ng-app="app" ng-controller="ctr ...

  7. (原创) jetson tk1 初始化

    1. 相关的网站: 1. Jetson TK1 support   https://developer.nvidia.com/jetson-tk1-support 2.official Wiki fo ...

  8. void (*f(int, void (*)(int)))(int) 函数解析

    函数指针 今天与几个同学看到了一个函数指针定义: void (*f(int, void (*)(int)))(int) 以前在C trap pit fails里面见过,但是文章里面介绍的很详细,但是往 ...

  9. 【vc】5_文本编程

    1.插入符(Caret): (1) 文本插入符 函数的原型声明:(CWnd类) void CreateSolidCaret ( int Nwidth, int nHeight ); ·nwidth:指 ...

  10. UVa 10098: Generating Fast

    这道题要求按字典序生成字符串的全排列,不可重复(但字符可以重复,且区分大小写). 基本思路是先对输入的字符串按字典序排序,然后从第一位开始递归,从所有输入的字符中选出一个填充,然后再选第二位..... ...