Glide源碼解析之DiskCache

前言

在之前的文章Glide源碼解析之MemoryCache介紹了Glide的二級(jí)緩存MemoryCache,現(xiàn)在讓我們來(lái)看下三級(jí)緩存DiskCache。

獲取DiskCache

在上文Glide源碼解析之DecodeHelper我們講到DecodeHelper主要是起到了一個(gè)提供數(shù)據(jù)的作用, DiskCache同樣是通過(guò)DecoderHelper來(lái)通過(guò)diskCacheProvider獲取的,而diskCacheProvider的實(shí)現(xiàn)類為L(zhǎng)azyDiskCacheProvider,是由Engine在構(gòu)造函數(shù)里創(chuàng)建并傳遞給DecoderHelper的。LazyDiskCacheProvider的構(gòu)造函數(shù)參數(shù)為DiskCache.Factory,它的實(shí)現(xiàn)類為InternalCacheDiskCacheFactory,是在GlideBuilder的builde()里面創(chuàng)建并傳給Engine的。

    //DecodeHelper
    DiskCache getDiskCache() {
        return diskCacheProvider.getDiskCache();
    }
    
    //Engine
    Engine(MemoryCache cache,
           DiskCache.Factory diskCacheFactory,
           xxx) {
        this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory);
    }
    
    //GlideBuilder
    Glide builde(Context context){
        if (diskCacheFactory == null) {
            diskCacheFactory = new InternalCacheDiskCacheFactory(context);
        }

        if (engine == null) {
            engine =
                    new Engine(
                            memoryCache,
                            diskCacheFactory,
                            diskCacheExecutor,
                            sourceExecutor,
                            GlideExecutor.newUnlimitedSourceExecutor(),
                            animationExecutor,
                            isActiveResourceRetentionAllowed);
        }
    }

LazyDiskCacheProvider

這里對(duì)DiskCache用了單例模式來(lái)保存實(shí)例,它的創(chuàng)建則是由DiskCache.Factory來(lái)提供,也就是上面說(shuō)到的InternalCacheDiskCacheFactory。InternalCacheDiskCacheFactory繼承于DiskLruCacheFactory,DiskLruCacheFactory實(shí)現(xiàn)了DiskCache.Factory的接口,待會(huì)再看下這兩個(gè)類。

    private static class LazyDiskCacheProvider implements DecodeJob.DiskCacheProvider {

        private final DiskCache.Factory factory;
        private volatile DiskCache diskCache;

        LazyDiskCacheProvider(DiskCache.Factory factory) {
            this.factory = factory;
        }

        @VisibleForTesting
        synchronized void clearDiskCacheIfCreated() {
            if (diskCache == null) {
                return;
            }
            diskCache.clear();
        }

        @Override
        public DiskCache getDiskCache() {
            if (diskCache == null) {
                synchronized (this) {
                    if (diskCache == null) {
                        diskCache = factory.build();    //由DiskLruCacheFactory去實(shí)例化DiskCache
                    }
                    if (diskCache == null) {
                        diskCache = new DiskCacheAdapter();
                    }
                }
            }
            return diskCache;
        }
    }

DiskCache.Factory

InternalCacheDiskCacheFactory只是提供了構(gòu)造函數(shù),并最終調(diào)用了DiskLruCacheFactory的構(gòu)造函數(shù),給它提供了diskCacheSize和cacheDirectoryGetter,build()還是由DiskLruCacheFactory來(lái)實(shí)現(xiàn)的。

在builde()里面首先檢查緩存目錄是否為null,這個(gè)一般不為null,目錄路徑為data/data/你的app/cache/image_manager_disk_cache。最終返回的DiskCache實(shí)現(xiàn)類則是DiskLruCacheWrapper。

    //DiskLruCacheFactory
    public DiskCache build() {
        File cacheDir = cacheDirectoryGetter.getCacheDirectory();

        if (cacheDir == null) {
            return null;
        }

        if (!cacheDir.mkdirs() && (!cacheDir.exists() || !cacheDir.isDirectory())) {
            return null;
        }

        return DiskLruCacheWrapper.create(cacheDir, diskCacheSize);
    }
    
    //DiskLruCacheWrapper
    public static DiskCache create(File directory, long maxSize) {
        return new DiskLruCacheWrapper(directory, maxSize);
    }
    
//InternalCacheDiskCacheFactory
public final class InternalCacheDiskCacheFactory extends DiskLruCacheFactory {

    public InternalCacheDiskCacheFactory(Context context) {
        this(context, DiskCache.Factory.DEFAULT_DISK_CACHE_DIR/*image_manager_disk_cache*/,
        DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE/*250M*/);
    }
    
    public InternalCacheDiskCacheFactory(final Context context, final String diskCacheName,
                                       long diskCacheSize) {
        super(new CacheDirectoryGetter() {
            @Override
            public File getCacheDirectory() {
                
                File cacheDirectory = context.getCacheDir();
                if (cacheDirectory == null) {
                    return null;
                }
                
                if (diskCacheName != null) {
                    //緩存目錄為cache/image_manager_disk_cache
                    return new File(cacheDirectory, diskCacheName);
                }
                
                return cacheDirectory;
            }
            
        }, diskCacheSize);
    }

}

DiskCache

DiskCache的實(shí)現(xiàn)類為DiskLruCacheWrapper,但是它并不進(jìn)行實(shí)際的磁盤緩存,具體的操作是由DiskLruCache來(lái)實(shí)現(xiàn)的。由名字可以看出這里使用了裝飾模式來(lái)對(duì)DiskLruCache增加一些功能。

public interface DiskCache {

  /**
   * 根據(jù)key獲取緩存文件
   */
  @Nullable
  File get(Key key);

  /**
   * 寫入緩存文件
   */
  void put(Key key, Writer writer);

  /**
   * 刪除緩存文件
   */
  void delete(Key key);

  /**
   * 清空緩存文件(全刪)
   */
  void clear();
}

public class DiskLruCacheWrapper implements DiskCache {

    private static final int APP_VERSION = 1;
    private static final int VALUE_COUNT = 1;

    private final SafeKeyGenerator safeKeyGenerator;   //用來(lái)構(gòu)建String類型的磁盤緩存Key
    private final File directory;
    private final long maxSize;
    private final DiskCacheWriteLocker writeLocker = new DiskCacheWriteLocker();
    private DiskLruCache diskLruCache;
    
    private synchronized DiskLruCache getDiskCache() throws IOException {
        if (diskLruCache == null) {
            diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize);
        }
        return diskLruCache;
    }
    
}

DiskLruCache

DiskLruCache和MemoryCache一樣是使用LinkedHashMap來(lái)實(shí)現(xiàn)LRU算法,但是LinkedHashMap只能對(duì)內(nèi)存數(shù)據(jù)進(jìn)行處理,但是要是App關(guān)掉下次再打開不就是沒(méi)最近使用記錄了? 所以DiskLruCache將對(duì)數(shù)據(jù)的操作都寫進(jìn)了一個(gè)日志文件里,當(dāng)初始化時(shí)先從日志文件中獲取歷史緩存以及讀取順序,之后再操作時(shí)也會(huì)同步更新到日志文件。

public final class DiskLruCache implements Closeable {

    //日志文件相關(guān)
    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;
    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;      //臨時(shí)日志文件
    private final File journalFileBackup;   //日志備份文件
    private final int appVersion;
    private long maxSize;                   //最大緩存大小
    private long size = 0;                  //當(dāng)前緩存大小
    private final int valueCount;           //值為1
    private Writer journalWriter;           //快速讀寫文件使用 Writer
    private final LinkedHashMap<String, Entry> lruEntries =
            new LinkedHashMap<String, Entry>(0, 0.75f, true);
    
}

//日志文件格式
libcore.io.DiskLruCache     //MAGIC
1                           //VERSION_1
1                           //appVersion
1                           //valueCount

DIRTY 4244bd8b60e86cb88a8d24052c5a3d52da7091a289a9d3c09b98531260ce0171            //新寫入LinkedHashMap的數(shù)據(jù),狀態(tài)為DIRTY 后面跟著的一串是key
CLEAN 4244bd8b60e86cb88a8d24052c5a3d52da7091a289a9d3c09b98531260ce0171 8441       //將數(shù)據(jù)寫進(jìn)磁盤后狀態(tài)為CLEAN,最后的數(shù)字是圖片大小
READ 4244bd8b60e86cb88a8d24052c5a3d52da7091a289a9d3c09b98531260ce0171             //讀了之后狀態(tài)為READ
REMOVE 64af945d99537d3f777a76dc62012d9c2368f33f145bbf592fa11f28489f8142           //刪除的狀態(tài)為REMOVE

//日志文件記錄的是操作狀態(tài),執(zhí)行了新的操作之后并不會(huì)把之前的刪了,只是會(huì)添加一條新的記錄。

open()

在這里創(chuàng)建DiskLruCache

    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");
        }

        File backupFile = new File(directory, JOURNAL_FILE_BACKUP);
        if (backupFile.exists()) {
            //如果有日志備份文件
            File journalFile = new File(directory, JOURNAL_FILE);
            if (journalFile.exists()) {
                // 如果日志文件存在則刪除備份文件
                backupFile.delete();
            } else {
                //如果日志文件不存在則把備份文件重命名為日志文件
                renameTo(backupFile, journalFile, false);
            }
        }

        DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
        if (cache.journalFile.exists()) {
            try {
                cache.readJournal();        //讀取日志文件
                cache.processJournal();     //處理日志文件
                return cache;               //如果沒(méi)有異常的話直接返回
            } catch (IOException journalIsCorrupt) {
                System.out
                        .println("DiskLruCache "
                                + directory
                                + " is corrupt: "
                                + journalIsCorrupt.getMessage()
                                + ", removing");
                cache.delete();             //刪除全部緩存文件
            }
        }

        //上面出現(xiàn)異常后會(huì)刪除全部緩存文件,這里重新生成DiskLruCache以及日志文件
        directory.mkdirs();
        cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
        cache.rebuildJournal();
        return cache;
    }

readJournal()

在這里讀取日志文件,將日志文件記錄的數(shù)據(jù)寫入LinkedHashMap。

    private void readJournal() throws IOException {
        StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII);
        try {
            String magic = reader.readLine();
            String version = reader.readLine();
            String appVersionString = reader.readLine();
            String valueCountString = reader.readLine();
            String blank = reader.readLine();
            
            //檢查格式是否正確
            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 + "]");
            }

            int lineCount = 0;
            while (true) {
                try {
                    //一行行讀取日志文件
                    readJournalLine(reader.readLine());
                    lineCount++;
                } catch (EOFException endOfJournal) {
                    break;
                }
            }
            redundantOpCount = lineCount - lruEntries.size();

            if (reader.hasUnterminatedLine()) {
                rebuildJournal();
            } else {
                journalWriter = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(journalFile, true), Util.US_ASCII));
            }
        } finally {
            Util.closeQuietly(reader);
        }
    }
    
    private void readJournalLine(String line) throws IOException {
        int firstSpace = line.indexOf(' ');             //第一個(gè)空格的位置,它的前面是狀態(tài),后面是key
        if (firstSpace == -1) {
            throw new IOException("unexpected journal line: " + line);
        }

        int keyBegin = firstSpace + 1;
        int secondSpace = line.indexOf(' ', keyBegin);  //如果狀態(tài)是CLEAN則會(huì)有兩個(gè)空格,它的前面是key,后面是圖片大小
        final String key;
        if (secondSpace == -1) {
            key = line.substring(keyBegin);
            
            //如果狀態(tài)是REMOVE則從LinkedHashMap中刪除
            if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) {
                lruEntries.remove(key);
                return;
            }
        } else {
            key = line.substring(keyBegin, secondSpace);
        }

        Entry entry = lruEntries.get(key);
        if (entry == null) {
            //Entry里面根據(jù)key來(lái)獲取緩存文件
            entry = new Entry(key);
            //將獲取到的緩存文件添加到LinkedHashMap中
            lruEntries.put(key, entry);
        }

        if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) {
            //如果狀態(tài)是CLEAN則代表圖片已經(jīng)寫入緩存文件了
            String[] parts = line.substring(secondSpace + 1).split(" ");
            entry.readable = true;
            entry.currentEditor = null;
            entry.setLengths(parts);
        } else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) {
            //狀態(tài)是DIRTY則以后會(huì)通過(guò)Editor來(lái)寫入緩存文件,也會(huì)通過(guò)判斷currentEditor是否為null來(lái)來(lái)確定是否是DIRTY的數(shù)據(jù)
            entry.currentEditor = new Editor(entry);
        } else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) {
            // 因?yàn)樯厦嬲{(diào)用過(guò)lruEntries.get(key),LinkedHashMap會(huì)自動(dòng)調(diào)整訪問(wèn)順序,所以這里不需要再執(zhí)行其他操作
        } else {
            throw new IOException("unexpected journal line: " + line);
        }
    }

put()

首先會(huì)使用SafeKeyGenerator來(lái)對(duì)key進(jìn)行sha256BytesToHex()計(jì)算,接著判斷是否已經(jīng)有緩存數(shù)據(jù),如果沒(méi)有則會(huì)先把圖片寫進(jìn)DirtyFile,最后再重命名為CleanFile。

    @Override
    public void put(Key key, Writer writer) {
        String safeKey = safeKeyGenerator.getSafeKey(key);
        //使用磁盤緩存寫鎖同步代碼
        writeLocker.acquire(safeKey);
        try {
            try {
                // 如果已經(jīng)有緩存數(shù)據(jù)了,則不覆蓋,直接返回。因?yàn)閗ey計(jì)算的唯一性,使得一個(gè)key只會(huì)對(duì)應(yīng)一個(gè)value。
                DiskLruCache diskCache = getDiskCache();
                Value current = diskCache.get(safeKey);
                if (current != null) {
                    return;
                }

                DiskLruCache.Editor editor = diskCache.edit(safeKey);
                if (editor == null) {
                    throw new IllegalStateException("Had two simultaneous puts for: " + safeKey);
                }
                try {
                    //這里獲取的是DirtyFile
                    File file = editor.getFile(0);
                    
                    //將圖片寫進(jìn)DirtyFile
                    if (writer.write(file)) {
                        editor.commit();        //將DirtyFile重命名為CleanFile
                    }
                } finally {
                    editor.abortUnlessCommitted();
                }
            } catch (IOException e) {
                if (Log.isLoggable(TAG, Log.WARN)) {
                    Log.w(TAG, "Unable to put to disk cache", e);
                }
            }
        } finally {
            writeLocker.release(safeKey);
        }
    }
    
    //DiskLruCache
    public Editor edit(String key) throws IOException {
        return edit(key, ANY_SEQUENCE_NUMBER);
    }

    private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
        checkNotClosed();
        Entry entry = lruEntries.get(key);
        if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null
                || entry.sequenceNumber != expectedSequenceNumber)) {
            return null; 
        }
        
        if (entry == null) {
            entry = new Entry(key);
            lruEntries.put(key, entry);     //存新數(shù)據(jù)到LinkedHashMap
        } else if (entry.currentEditor != null) {
            return null;
        }

        Editor editor = new Editor(entry);
        entry.currentEditor = editor;

        // 往日志文件添加一行狀態(tài)為DIRTY的記錄
        journalWriter.append(DIRTY);
        journalWriter.append(' ');
        journalWriter.append(key);
        journalWriter.append('\n');
        journalWriter.flush();
        return editor;
    }
    

將臨時(shí)文件改為正式的緩存文件

    public File getFile(int index) throws IOException {
        synchronized (DiskLruCache.this) {
            if (entry.currentEditor != this) {
                throw new IllegalStateException();
            }
            
            //readable默認(rèn)為false
            if (!entry.readable) {
                written[index] = true;  //這里會(huì)賦值為true
            }
            File dirtyFile = entry.getDirtyFile(index);
            if (!directory.exists()) {
                directory.mkdirs();
            }
            return dirtyFile;
        }
    }
        
    public void commit() throws IOException {
        completeEdit(this, true);
        committed = true;
    }
        
    private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
        Entry entry = editor.entry;
        if (entry.currentEditor != editor) {
            throw new IllegalStateException();
        }

        if (success && !entry.readable) {
            for (int i = 0; i < valueCount; i++) {
                //上面在getFile()時(shí)賦值為true了,所以不會(huì)進(jìn)入這里。
                if (!editor.written[i]) {
                    editor.abort();
                    throw new IllegalStateException("Newly created entry didn't create value for index " + i);
                }
                
                //在getFile()之后就調(diào)用了writer.write(file),所以DirtyFile也是存在的,不會(huì)進(jìn)入里面。
                if (!entry.getDirtyFile(i).exists()) {
                    editor.abort();
                    return;
                }
            }
        }

        //valueCount為1
        for (int i = 0; i < valueCount; i++) {
            File dirty = entry.getDirtyFile(i);
            if (success) {
                if (dirty.exists()) {   
                    //將DirtyFile重命名為CleanFile,文件名為(key.0),并計(jì)算當(dāng)前緩存大小
                    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) {
            //往日志文件添加狀態(tài)為CLEAN的記錄
            entry.readable = true;          //賦值為true
            journalWriter.append(CLEAN);
            journalWriter.append(' ');
            journalWriter.append(entry.key);
            journalWriter.append(entry.getLengths());
            journalWriter.append('\n');

            if (success) {
                entry.sequenceNumber = nextSequenceNumber++;
            }
        } else {
            lruEntries.remove(entry.key);
            journalWriter.append(REMOVE);
            journalWriter.append(' ');
            journalWriter.append(entry.key);
            journalWriter.append('\n');
        }
        journalWriter.flush();

        if (size > maxSize || journalRebuildRequired()) {
            executorService.submit(cleanupCallable);
        }
    }

get()

獲取緩存文件,先根據(jù)key獲取對(duì)應(yīng)的Entry,如果存在則判斷是否可讀(磁盤有對(duì)應(yīng)的圖片緩存),如果緩存文件存在則往日志文件添加一條狀態(tài)為READ的記錄,最后把數(shù)據(jù)封裝進(jìn)Value并返回。

    public File get(Key key) {
        String safeKey = safeKeyGenerator.getSafeKey(key);

        File result = null;
        try {
            //Value只是DiskLruCache里面的一個(gè)內(nèi)部類,主要起到封裝數(shù)據(jù)的作用,并不是實(shí)際緩存的值。
            final DiskLruCache.Value value = getDiskCache().get(safeKey);
            if (value != null) {
                //返回緩存的文件,即是CleanFile
                result = value.getFile(0);
            }
        } catch (IOException e) {
            if (Log.isLoggable(TAG, Log.WARN)) {
                Log.w(TAG, "Unable to get from disk cache", e);
            }
        }
        return result;
    }
    
    //DiskLruCache
    public synchronized Value get(String key) throws IOException {
        checkNotClosed();
        Entry entry = lruEntries.get(key);
        if (entry == null) {
            return null;
        }

        //在上面的completeEdit()中會(huì)將readable賦值為true
        if (!entry.readable) {
            return null;
        }

        for (File file : entry.cleanFiles) {
            // 判斷緩存文件是否存在
            if (!file.exists()) {
                return null;
            }
        }

        redundantOpCount++;
        
        //往日志文件添加一條狀態(tài)為READ的記錄
        journalWriter.append(READ);
        journalWriter.append(' ');
        journalWriter.append(key);
        journalWriter.append('\n');
        if (journalRebuildRequired()) {
            executorService.submit(cleanupCallable);
        }
        
        //將數(shù)據(jù)封裝進(jìn)Value并返回
        return new Value(key, entry.sequenceNumber, entry.cleanFiles, entry.lengths);
    }

delete()

刪除緩存,首先會(huì)將緩存文件刪除,然后往日志文件添加一條狀態(tài)為REMOVE的記錄,最后把LinkedHashMap中的數(shù)據(jù)也刪除。


    @Override
    public void delete(Key key) {
        String safeKey = safeKeyGenerator.getSafeKey(key);
        try {
            getDiskCache().remove(safeKey);
        } catch (IOException e) {
            if (Log.isLoggable(TAG, Log.WARN)) {
                Log.w(TAG, "Unable to delete from disk cache", e);
            }
        }
    }

    //DisLruCache
    public synchronized boolean remove(String key) throws IOException {
        checkNotClosed();
        Entry entry = lruEntries.get(key);
        
        //在completeEdit()中會(huì)將currentEditor置為null
        if (entry == null || entry.currentEditor != null) {
            return false;
        }

        for (int i = 0; i < valueCount; i++) {
            File file = entry.getCleanFile(i);
            //刪除CleanFile
            if (file.exists() && !file.delete()) {
                throw new IOException("failed to delete " + file);
            }
            size -= entry.lengths[i];
            entry.lengths[i] = 0;
        }

        redundantOpCount++;
        
        //往日志文件添加一條狀態(tài)為REMOVE的記錄
        journalWriter.append(REMOVE);
        journalWriter.append(' ');
        journalWriter.append(key);
        journalWriter.append('\n');

        //在LinkedHashMap中也刪除
        lruEntries.remove(key);

        if (journalRebuildRequired()) {
            executorService.submit(cleanupCallable);
        }

        return true;
    }

clear()

刪除全部磁盤緩存數(shù)據(jù)。

    @Override
    public synchronized void clear() {
        try {
            getDiskCache().delete();
        } catch (IOException e) {
            if (Log.isLoggable(TAG, Log.WARN)) {
                Log.w(TAG, "Unable to clear disk cache or disk cache cleared externally", e);
            }
        } finally {
            resetDiskCache();   //diskLruCache = null;
        }
    }
    
    //DiskLruCache
    public void delete() throws IOException {
        close();
        Util.deleteContents(directory);
    }
    
    public synchronized void close() throws IOException {
        if (journalWriter == null) {
            //如果之前已經(jīng)執(zhí)行過(guò)close()的則直接返回
            return; 
        }
        for (Entry entry : new ArrayList<Entry>(lruEntries.values())) {
            if (entry.currentEditor != null) {
                //刪除DirtyFile,接著在LinkedHashMap中刪除對(duì)應(yīng)的數(shù)據(jù),最后往日志文件添加一條狀態(tài)為REMOVE的記錄
                entry.currentEditor.abort();
            }
        }
        trimToSize();
        journalWriter.close();
        journalWriter = null;
    }
    
    public void abort() throws IOException {
        //在上面有分析,第二個(gè)參數(shù)不一樣而已
        completeEdit(this, false);
    }
    
    //如果文件存在則刪除
    private static void deleteIfExists(File file) throws IOException {
        if (file.exists() && !file.delete()) {
            throw new IOException();
        }
    }
    
    //遞歸刪除文件夾及里面的文件
    static void deleteContents(File dir) throws IOException {
        File[] files = dir.listFiles();
        if (files == null) {
            throw new IOException("not a readable directory: " + dir);
        }
        
        for (File file : files) {
            if (file.isDirectory()) {
                deleteContents(file);
            }
            if (!file.delete()) {
                throw new IOException("failed to delete file: " + file);
            }
        }
     }

總結(jié)

DiskLruCacheWrapper實(shí)現(xiàn)了DiskCache接口來(lái)提供磁盤緩存的操作,但是具體的操作則是由DiskLruCache來(lái)實(shí)現(xiàn)。DiskLruCache內(nèi)部同樣是使用了LinkedHashMap來(lái)實(shí)現(xiàn)最近最少使用原則,同時(shí)還會(huì)將所有的操作記錄寫入日志文件。當(dāng)初始化時(shí)LinkedHashMap就可以根據(jù)日志文件來(lái)恢復(fù)數(shù)據(jù)和使用順序。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容