package com.tadpolemusic.media.http; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; import java.util.Properties; import android.os.Environment; import com.itap.voiceemoticon.api.util.MD5Util; /** * <br>========================== * <br> author:Zenip * <br> email:lxyczh@gmail.com * <br> create:2013-2-11 * <br>========================== */ public class HttpCache { private static final String CONTENT_RANGE = "Content-Range"; private static final String CONTENT_LENGTH = "Content-Length"; private static final String MUSIC_CACHE_DIR = "/tadpole/music"; private String mCachePath; private HttpGetProxy mHttpGetProxy; public HttpCache(String cachePath, HttpGetProxy httpGetProxy) { mCachePath = cachePath; mHttpGetProxy = httpGetProxy; } public boolean exist() { final ByteCache cacheHeader = readCacheResponseHeader(mCachePath); final ByteCache cacheBody = readCacheBody(mCachePath); return cacheHeader.isNotEmpty() && cacheBody.isNotEmpty(); } public ByteCache readCacheResponseHeader(String musicUrl) { return readCache(musicUrl, ".header"); } public ByteCache readCacheBody(String musicUrl) { return readCache(musicUrl, ".body"); } public String getCacheHeader() { final ByteCache cacheHeader = readCacheResponseHeader(mCachePath); byte[] cacheHeaderBytes = cacheHeader.getBytes(); return new String(cacheHeaderBytes); } public int getContentLength() { Properties properties = readProperties(); String contentLength = properties.getProperty(CONTENT_LENGTH); if ("".equals(contentLength) || contentLength == null) { contentLength = "0"; } return Integer.valueOf(contentLength); } public boolean writeHeaderWithModified(final OutputStream dstOutput, int contentLength, int statusCode, int rangeStart) throws IOException { System.out.println("=====>local writing response header by using cache"); final ByteCache cacheHeader = readCacheResponseHeader(mCachePath); String header = cacheHeader.getString(); header = HttpParser.replaceStatusCode(header, statusCode); if (rangeStart == 0) { header = HttpParser.removeHeader(header, CONTENT_RANGE); header = HttpParser.replaceOrAddHeader(header, CONTENT_LENGTH, "" + contentLength); } else { int tmpContentLength = contentLength - rangeStart; header = HttpParser.addContentRange(header, rangeStart, tmpContentLength, contentLength); header = HttpParser.replaceOrAddHeader(header, CONTENT_LENGTH, "" + tmpContentLength); } System.out.println("----->localCacheHeader:" + header); final byte[] cacheHeaderBytes = header.getBytes(); dstOutput.write(cacheHeaderBytes); return true; } public long getBodyLength() { final ByteCache cacheBody = readCacheBody(mCachePath); return cacheBody.getLength(); } /** * @param dstOutput * @param rangeStart * @return * @throws IOException */ public int writeBodyCacheToLocalOut(final OutputStream dstOutput, long rangeStart, int byteCount) throws IOException { final ByteCache cacheHeader = readCacheResponseHeader(mCachePath); final ByteCache cacheBody = readCacheBody(mCachePath); System.out.println("=====>local write cache body range = (" + rangeStart + ", " + cacheBody.getLength() + ")"); int byteRead = 0; final byte[] cacheHeaderBytes = cacheHeader.getBytes(); int contentLength = HttpParser.getContentLength(new String(cacheHeaderBytes)); int byteCountToRead = byteCount; int lastByteRead = 0; System.out.println("----->local cache response content-length:" + contentLength + " cacheBody length:" + cacheBody.getLength()); if (contentLength != -1) { byte[] buffer = new byte[5120]; RandomAccessFile ras = cacheBody.openRAS(); ras.seek(rangeStart); int tmpByteRead = 0; while ((tmpByteRead = ras.read(buffer)) != -1) { lastByteRead = byteRead; byteRead += tmpByteRead; if (byteRead > byteCountToRead) { int writeByteCount = byteCountToRead - lastByteRead; dstOutput.write(buffer, 0, writeByteCount); } else { dstOutput.write(buffer, 0, tmpByteRead); } } try { ras.close(); } catch (Exception e) { e.printStackTrace(); } } System.out.println("=====>write cache body to local finish . Totally byteRead = " + byteRead); return byteRead; } public Properties readProperties() { String cacheFilePath = getCacheFilePath(mCachePath, ".ini"); Properties properties = new Properties(); FileInputStream in = null; try { File f = new File(cacheFilePath); if (!f.exists()) { f.createNewFile(); } in = new FileInputStream(new File(cacheFilePath)); properties.load(in); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); in = null; } } catch (Exception e) { e.printStackTrace(); } } return properties; } public void writeProperties(String musicUrl, Properties properties) { String cacheFilePath = getCacheFilePath(musicUrl, ".ini"); FileOutputStream out = null; try { out = new FileOutputStream(new File(cacheFilePath)); properties.store(out, ""); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); out = null; } } catch (Exception e) { e.printStackTrace(); } } } public void writeCacheResponseHeader(byte[] data) { writeCache(mCachePath, ".header", 0, data); } public void writeCacheResponseBody(int seekPos, byte[] data) { writeCache(mCachePath, ".body", seekPos, data); } public RandomAccessFile openCacheResponseBody() { String cacheFilePath = getCacheFilePath(mCachePath, ".body"); File cacheFile = new File(cacheFilePath); RandomAccessFile ras = null; try { if (cacheFile.exists() && cacheFile.isDirectory()) { cacheFile.delete(); cacheFile.createNewFile(); } else { cacheFile.createNewFile(); } ras = new RandomAccessFile(cacheFile, "rws"); } catch (Exception e) { e.printStackTrace(); } return ras; } //---------------------------------------------- // 读写基础方法 //---------------------------------------------- private String getCacheFilePath(String key, String suffix) { String cacheFilePath = defaultCacheDir() + File.separator + MD5Util.getMD5(key.getBytes()) + suffix; return cacheFilePath; } private void writeCache(String key, String suffix, int seekPos, byte data[]) { String cacheFilePath = getCacheFilePath(key, suffix); File cacheFile = new File(cacheFilePath); RandomAccessFile ras = null; try { if (cacheFile.exists() && cacheFile.isDirectory()) { cacheFile.delete(); cacheFile.createNewFile(); } else { cacheFile.createNewFile(); } ras = new RandomAccessFile(cacheFile, "rws"); ras.seek(seekPos); ras.write(data); } catch (Exception e) { e.printStackTrace(); } finally { close(ras); } } private ByteCache readCache(String key, String suffix) { String cacheFilePath = getCacheFilePath(key, suffix); File cacheFile = new File(cacheFilePath); return new ByteCache(cacheFile); } private String defaultCacheDir() { if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { File sdFile = Environment.getExternalStorageDirectory(); String sdDirPath = sdFile.getAbsolutePath() + File.separator + MUSIC_CACHE_DIR; File file = new File(sdDirPath); if (file.exists()) { file.mkdirs(); } return sdDirPath; } return null; } private void close(Closeable obj) { try { if (obj != null) { obj.close(); } } catch (IOException e) { e.printStackTrace(); } } }