/**
   * Initializes the DiskBasedCache by scanning for all files currently in the specified root
   * directory. Creates the root directory if necessary.
   */
  @Override
  public synchronized void initialize() {
    if (!mRootDirectory.exists()) {
      if (!mRootDirectory.mkdirs()) {
        VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());
      }
      return;
    }

    File[] files = mRootDirectory.listFiles();
    if (files == null) {
      return;
    }
    for (File file : files) {
      BufferedInputStream fis = null;
      try {
        fis = new BufferedInputStream(new FileInputStream(file));
        CacheHeader entry = CacheHeader.readHeader(fis);
        entry.size = file.length();
        putEntry(entry.key, entry);
      } catch (IOException e) {
        if (file != null) {
          file.delete();
        }
      } finally {
        try {
          if (fis != null) {
            fis.close();
          }
        } catch (IOException ignored) {
        }
      }
    }
  }
  /** Returns the cache entry with the specified key if it exists, null otherwise. */
  @Override
  public synchronized Entry get(String key) {
    CacheHeader entry = mEntries.get(key);
    // if the entry does not exist, return.
    if (entry == null) {
      return null;
    }

    File file = getFileForKey(key);
    CountingInputStream cis = null;
    try {
      cis = new CountingInputStream(new BufferedInputStream(new FileInputStream(file)));
      CacheHeader.readHeader(cis); // eat header
      byte[] data = streamToBytes(cis, (int) (file.length() - cis.bytesRead));
      return entry.toCacheEntry(data);
    } catch (IOException e) {
      VolleyLog.d("%s: %s", file.getAbsolutePath(), e.toString());
      remove(key);
      return null;
    } finally {
      if (cis != null) {
        try {
          cis.close();
        } catch (IOException ioe) {
          return null;
        }
      }
    }
  }
 /** Removes the specified key from the cache if it exists. */
 @Override
 public synchronized void remove(String key) {
   boolean deleted = getFileForKey(key).delete();
   removeEntry(key);
   if (!deleted) {
     VolleyLog.d(
         "Could not delete cache entry for key=%s, filename=%s", key, getFilenameForKey(key));
   }
 }
 /** Clears the cache. Deletes all cached files from disk. */
 @Override
 public synchronized void clear() {
   File[] files = mRootDirectory.listFiles();
   if (files != null) {
     for (File file : files) {
       file.delete();
     }
   }
   mEntries.clear();
   mTotalSize = 0;
   VolleyLog.d("Cache cleared.");
 }
  /**
   * Prunes the cache to fit the amount of bytes specified.
   *
   * @param neededSpace The amount of bytes we are trying to fit into the cache.
   */
  private void pruneIfNeeded(int neededSpace) {
    if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes) {
      return;
    }
    if (VolleyLog.DEBUG) {
      VolleyLog.v("Pruning old cache entries.");
    }

    long before = mTotalSize;
    int prunedFiles = 0;
    long startTime = SystemClock.elapsedRealtime();

    Iterator<Map.Entry<String, CacheHeader>> iterator = mEntries.entrySet().iterator();
    while (iterator.hasNext()) {
      Map.Entry<String, CacheHeader> entry = iterator.next();
      CacheHeader e = entry.getValue();
      boolean deleted = getFileForKey(e.key).delete();
      if (deleted) {
        mTotalSize -= e.size;
      } else {
        VolleyLog.d(
            "Could not delete cache entry for key=%s, filename=%s",
            e.key, getFilenameForKey(e.key));
      }
      iterator.remove();
      prunedFiles++;

      if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {
        break;
      }
    }

    if (VolleyLog.DEBUG) {
      VolleyLog.v(
          "pruned %d files, %d bytes, %d ms",
          prunedFiles, (mTotalSize - before), SystemClock.elapsedRealtime() - startTime);
    }
  }
 /** Puts the entry with the specified key into the cache. */
 @Override
 public synchronized void put(String key, Entry entry) {
   pruneIfNeeded(entry.data.length);
   File file = getFileForKey(key);
   try {
     BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(file));
     CacheHeader e = new CacheHeader(key, entry);
     boolean success = e.writeHeader(fos);
     if (!success) {
       fos.close();
       VolleyLog.d("Failed to write header for %s", file.getAbsolutePath());
       throw new IOException();
     }
     fos.write(entry.data);
     fos.close();
     putEntry(key, e);
     return;
   } catch (IOException e) {
   }
   boolean deleted = file.delete();
   if (!deleted) {
     VolleyLog.d("Could not clean up file %s", file.getAbsolutePath());
   }
 }
 /** Writes the contents of this CacheHeader to the specified OutputStream. */
 public boolean writeHeader(OutputStream os) {
   try {
     writeInt(os, CACHE_MAGIC);
     writeString(os, key);
     writeString(os, etag == null ? "" : etag);
     writeLong(os, serverDate);
     writeLong(os, lastModified);
     writeLong(os, ttl);
     writeLong(os, softTtl);
     writeStringStringMap(responseHeaders, os);
     os.flush();
     return true;
   } catch (IOException e) {
     VolleyLog.d("%s", e.toString());
     return false;
   }
 }