Android 开源项目DiskLruCache解析使用
来源:互联网 发布:mysql存储小说内容 编辑:程序博客网 时间:2024/05/22 12:55
DiskLruCache 硬盘缓存,非Google官方编写,但获得官方承认, 只需要下载下来放到项目中就行。
journal文件
这个日志文件,关系着DiskLruCache的正常使用,里面记录了每条缓存,下面看看里面信息
第一行是固定的字符串,第二行是DiskLruCache的版本号,这个值为1,第三行是APP的版本号,每当更新版本时会清除缓存,第四行是valueCount的值,在open时传入,一般为1,第五行是个空行。在下面就是缓存的信息
分别有几种前缀,DIRTY脏数据,当我们调用DiskLruCache的edit()方法时就会写入一个DIRTY,后面是缓存的key;CLEAN,当调用了commit方法后,会写入一条CLEAN;REMOVE,当调用absort方法,写入缓存失败,会产生一条REMOVE;READ,当读取一条缓存时会写入一条READ。
open获得实例
DiskLruCache 不是new出来的,而是通过一个open函数获得实例
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) throws IOException { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } if (valueCount <= 0) { throw new IllegalArgumentException("valueCount <= 0"); } //根据参数创建对象赋值 DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); //判断日志文件是否存在 if (cache.journalFile.exists()) { try { //读取日志文件 cache.readJournal(); cache.processJournal(); //写日志文件的Writer cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true), IO_BUFFER_SIZE); return cache; } catch (IOException journalIsCorrupt) {// System.logW("DiskLruCache " + directory + " is corrupt: "// + journalIsCorrupt.getMessage() + ", removing"); //删除所有缓存数据 cache.delete(); } } // create a new empty cache directory.mkdirs(); cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); //创建日志文件 cache.rebuildJournal(); return cache; }主要就是创建对象,读取或者创建日志文件。
看看void readJournal()
private void readJournal() throws IOException { InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE); try { //这一段一般是文件头的信息 String magic = readAsciiLine(in); String version = readAsciiLine(in); String appVersionString = readAsciiLine(in); String valueCountString = readAsciiLine(in); String blank = readAsciiLine(in); if (!MAGIC.equals(magic) || !VERSION_1.equals(version) || !Integer.toString(appVersion).equals(appVersionString) || !Integer.toString(valueCount).equals(valueCountString) || !"".equals(blank)) { throw new IOException("unexpected journal header: [" + magic + ", " + version + ", " + valueCountString + ", " + blank + "]"); } //开始读日志信息 while (true) { try { //解析每一行的具体信息 readJournalLine(readAsciiLine(in)); } catch (EOFException endOfJournal) { break; } } } finally { //最后关闭输入流 closeQuietly(in); } }这个函数就是读取日志文件,前几行是日志的一些头信息,后面while循环解析日志,就是缓存的信息,解析出来放到了一个hash链表里面存储。
void rebuildJournal()
private synchronized void rebuildJournal() throws IOException { if (journalWriter != null) { journalWriter.close(); } //writer指向的journalFileTmp Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE); writer.write(MAGIC); writer.write("\n"); writer.write(VERSION_1); writer.write("\n"); writer.write(Integer.toString(appVersion)); writer.write("\n"); writer.write(Integer.toString(valueCount)); writer.write("\n"); writer.write("\n"); for (Entry entry : lruEntries.values()) { if (entry.currentEditor != null) { writer.write(DIRTY + ' ' + entry.key + '\n'); } else { writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); } } writer.close(); journalFileTmp.renameTo(journalFile); journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE); }主要就是创建journal
写入缓存
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { //校验journalWriter是否为空 checkNotClosed(); //校验key的合法性 validateKey(key); Entry entry = lruEntries.get(key); if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { return null; // snapshot is stale } //如果entry为空,创建一个并加入map里面 if (entry == null) { entry = new Entry(key); lruEntries.put(key, entry); } else if (entry.currentEditor != null) { return null; // another edit is in progress } Editor editor = new Editor(entry); entry.currentEditor = editor; // 写一条DIRTY journalWriter.write(DIRTY + ' ' + key + '\n'); journalWriter.flush(); return editor; }获得输出流
public OutputStream newOutputStream(int index) throws IOException { synchronized (DiskLruCache.this) { if (entry.currentEditor != this) { throw new IllegalStateException(); } return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index))); } }commit()操作
public void commit() throws IOException { if (hasErrors) { completeEdit(this, false); remove(entry.key); // the previous entry is stale } else { completeEdit(this, true); } } private synchronized void completeEdit(Editor editor, boolean success) throws IOException { Entry entry = editor.entry; if (entry.currentEditor != editor) { throw new IllegalStateException(); } // if this edit is creating the entry for the first time, every index must have a value if (success && !entry.readable) { for (int i = 0; i < valueCount; i++) { //不存在dirty类型的,则停止,抛出异常 if (!entry.getDirtyFile(i).exists()) { editor.abort(); throw new IllegalStateException("edit didn't create file " + i); } } } for (int i = 0; i < valueCount; i++) { //获得dirty类型的File File dirty = entry.getDirtyFile(i); if (success) { if (dirty.exists()) { //dirty转化为clean File clean = entry.getCleanFile(i); dirty.renameTo(clean); long oldLength = entry.lengths[i]; long newLength = clean.length(); entry.lengths[i] = newLength; size = size - oldLength + newLength; } } else { deleteIfExists(dirty); } } redundantOpCount++; entry.currentEditor = null; if (entry.readable | success) { entry.readable = true; journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); if (success) { entry.sequenceNumber = nextSequenceNumber++; } } else { lruEntries.remove(entry.key); journalWriter.write(REMOVE + ' ' + entry.key + '\n'); } //当缓存过大时,重新创建 if (size > maxSize || journalRebuildRequired()) { executorService.submit(cleanupCallable); } }
获取缓存
public synchronized Snapshot get(String key) throws IOException { checkNotClosed(); validateKey(key); Entry entry = lruEntries.get(key); if (entry == null) { return null; } if (!entry.readable) { return null; } /* * Open all streams eagerly to guarantee that we see a single published * snapshot. If we opened streams lazily then the streams could come * from different edits. */ InputStream[] ins = new InputStream[valueCount]; try { for (int i = 0; i < valueCount; i++) { ins[i] = new FileInputStream(entry.getCleanFile(i)); } } catch (FileNotFoundException e) { // a file must have been deleted manually! return null; } redundantOpCount++; //取出缓存后添加一条READ journalWriter.append(READ + ' ' + key + '\n'); //检查是否需要重构journal if (journalRebuildRequired()) { executorService.submit(cleanupCallable); } return new Snapshot(key, entry.sequenceNumber, ins); }返回SnapShot对象,通过这个对象就可以获得缓存的输入流。
其他一些方法
remove(String key)
移除特定的缓存,一般不使用,因为当缓存到达一定大小时,会去自定清理长期没用过的缓存
flush
同步内存的操作到journal文件中
delete()
删除所有缓存数据
close()
关闭DiskLruCache
小Demo
通过网络获取一张图片,缓存起来,点击按钮,通过缓存加载图片。
0 0
- Android 开源项目DiskLruCache解析使用
- Android DiskLruCache解析
- Android DiskLruCache完全解析
- Android-DiskLruCache源码解析
- Android DiskLruCache完全解析
- Android DiskLruCache磁盘缓存完全解析及使用
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android使用磁盘缓存DiskLruCache
- DiskLruCache解析
- Android之硬盘缓存DiskLrucache完全解析
- Android DiskLruCache完全解析,硬盘缓存
- Android DiskLruCache缓存完全解析(网易新闻)
- 起点
- POJ-1222 EXTENDED LIGHTS OUT【暴力枚举】
- POJ 3783 Balls(dp)
- 【疯狂Java】Java基础2
- JAVA基础再回首(十二)——Character类、Math类、Random类、System类
- Android 开源项目DiskLruCache解析使用
- 01背包 hdu 2564(饭卡)
- 论fork()函数与Linux中的多线程编程
- 使用WinPcap编程---把网络数据包存储到一个文件中
- Java 字符串对象池的作用是什么?
- UML中关于类之间的五种关系以及代码实现案例分析
- key length is more than 120
- 2016.08.15【初中部 NOIP提高组 】模拟赛C
- 如何将android studio项目转换成eclipse