-
String[] parts = line.split(" ");
-
if (parts.length < 2) {
-
throw new IOException("unexpected journal line: " + line);
-
}
-
String key = parts[1];
-
if (parts[0].equals(REMOVE) && parts.length == 2) {
-
lruEntries.remove(key);
-
return;
-
}
-
Entry entry = lruEntries.get(key);
-
if (entry == null) {
-
entry = new Entry(key);
-
lruEntries.put(key, entry);
-
}
-
if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) {
-
entry.readable = true;
-
entry.currentEditor = null;
-
entry.setLengths(Arrays.copyOfRange(parts, 2, parts.length));
-
} else if (parts[0].equals(DIRTY) && parts.length == 2) {
-
entry.currentEditor = new Editor(entry);
-
} else if (parts[0].equals(READ) && parts.length == 2) {
-
// this work was already done by calling lruEntries.get()
-
} else {
-
throw new IOException("unexpected journal line: " + line);
-
}
-
}
-
/**
-
* Computes the initial size and collects garbage as a part of opening the
-
* cache. Dirty entries are assumed to be inconsistent and will be deleted.
-
*/
-
private void processJournal() throws IOException {
-
deleteIfExists(journalFileTmp);
-
for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
-
Entry entry = i.next();
-
if (entry.currentEditor == null) {
-
for (int t = 0; t < valueCount; t++) {
-
size += entry.lengths[t];
-
}
-
} else {
-
entry.currentEditor = null;
-
for (int t = 0; t < valueCount; t++) {
-
deleteIfExists(entry.getCleanFile(t));
-
deleteIfExists(entry.getDirtyFile(t));
-
}
-
i.remove();
-
}
-
}
-
}
-
/**
-
* Creates a new journal that omits redundant information. This replaces the
-
* current journal if it exists.
-
*/
-
private synchronized void rebuildJournal() throws IOException {
-
if (journalWriter != null) {
-
journalWriter.close();
-
}
-
Writer writer = new BufferedWriter(new FileWriter(journalFileTmp));
-
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));
-
}
-
private static void deleteIfExists(File file) throws IOException {
-
try {
-
Libcore.os.remove(file.getPath());
-
} catch (ErrnoException errnoException) {
-
if (errnoException.errno != OsConstants.ENOENT) {
-
throw errnoException.rethrowAsIOException();
-
}
-
}
-
}
-
/**
-
* Returns a snapshot of the entry named {@code key}, or null if it doesn’t
-
* exist is not currently readable. If a value is returned, it is moved to
-
* the head of the LRU queue.
-
*/
-
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++;
-
journalWriter.append(READ + ’ ’ + key + ‘\n’);
-
if (journalRebuildRequired()) {
-
executorService.submit(cleanupCallable);
-
}
-
return new Snapshot(key, entry.sequenceNumber, ins);
-
}
-
/**
-
* Returns an editor for the entry named {@code key}, or null if another
-
* edit is in progress.
-
*/
-
public Editor edit(String key) throws IOException {
-
return edit(key, ANY_SEQUENCE_NUMBER);
-
}
-
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
-
checkNotClosed();
-
validateKey(key);
-
Entry entry = lruEntries.get(key);
-
if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER
-
&& (entry == null || entry.sequenceNumber != expectedSequenceNumber)) {
-
return null; // snapshot is stale
-
}
-
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;
-
// flush the journal before creating files to prevent file leaks
-
journalWriter.write(DIRTY + ’ ’ + key + ‘\n’);
-
journalWriter.flush();
-
return editor;
-
}
-
/**
-
* Returns the directory where this cache stores its data.
-
*/
-
public File getDirectory() {
-
return directory;
-
}
-
/**
-
* Returns the maximum number of bytes that this cache should use to store
-
* its data.
-
*/
-
public long maxSize() {
-
return maxSize;
-
}
-
/**
-
* Returns the number of bytes currently being used to store the values in
-
* this cache. This may be greater than the max size if a background
-
* deletion is pending.
-
*/
-
public synchronized long size() {
-
return size;
-
}
-
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++) {
-
if (!entry.getDirtyFile(i).exists()) {
-
editor.abort();
-
throw new IllegalStateException("edit didn’t create file " + i);
-
}
-
}
-
}
-
for (int i = 0; i < valueCount; i++) {
-
File dirty = entry.getDirtyFile(i);
-
if (success) {
-
if (dirty.exists()) {
-
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);
-
}
-
}
-
/**
-
* We only rebuild the journal when it will halve the size of the journal
-
* and eliminate at least 2000 ops.
-
*/
-
private boolean journalRebuildRequired() {
-
final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000;
-
return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD
-
&& redundantOpCount >= lruEntries.size();
-
}
-
/**
-
* Drops the entry for {@code key} if it exists and can be removed. Entries
-
* actively being edited cannot be removed.
-
*
-
* @return true if an entry was removed.
-
*/
-
public synchronized boolean remove(String key) throws IOException {
-
checkNotClosed();
-
validateKey(key);
-
Entry entry = lruEntries.get(key);
-
if (entry == null || entry.currentEditor != null) {
-
return false;
-
}
-
for (int i = 0; i < valueCount; i++) {
-
File file = entry.getCleanFile(i);
-
if (!file.delete()) {
-
throw new IOException("failed to delete " + file);
-
}
-
size -= entry.lengths[i];
-
entry.lengths[i] = 0;
-
}
-
redundantOpCount++;
-
journalWriter.append(REMOVE + ’ ’ + key + ‘\n’);
-
lruEntries.remove(key);
-
if (journalRebuildRequired()) {
-
executorService.submit(cleanupCallable);
-
}
-
return true;
-
}
-
/**
-
* Returns true if this cache has been closed.
-
*/
-
public boolean isClosed() {
-
return journalWriter == null;
-
}
-
private void checkNotClosed() {
-
if (journalWriter == null) {
-
throw new IllegalStateException(“cache is closed”);
-
}
-
}
-
/**
-
* Force buffered operations to the filesystem.
-
*/
-
public synchronized void flush() throws IOException {
-
checkNotClosed();
-
trimToSize();
-
journalWriter.flush();
-
}
-
/**
-
* Closes this cache. Stored values will remain on the filesystem.
-
*/
-
public synchronized void close() throws IOException {
-
if (journalWriter == null) {
-
return; // already closed
-
}
-
for (Entry entry : new ArrayList<Entry>(lruEntries.values())) {
-
if (entry.currentEditor != null) {
-
entry.currentEditor.abort();
-
}
-
}
-
trimToSize();
-
journalWriter.close();
-
journalWriter = null;
-
}
-
private void trimToSize() throws IOException {
-
while (size > maxSize) {
-
Map.Entry<String, Entry> toEvict = lruEntries.eldest();
-
remove(toEvict.getKey());
-
}
-
}
-
/**
-
* Closes the cache and deletes all of its stored values. This will delete
-
* all files in the cache directory including files that weren’t created by
-
* the cache.
-
*/
-
public void delete() throws IOException {
-
close();
-
IoUtils.deleteContents(directory);
-
}
-
private void validateKey(String key) {
-
if (key.contains(" “) || key.contains(”\n") || key.contains(“\r”)) {
-
throw new IllegalArgumentException(
-
“keys must not contain spaces or newlines: \”" + key + “\”");
-
}
-
}
-
private static String inputStreamToString(InputStream in) throws IOException {
-
return Streams.readFully(new InputStreamReader(in, Charsets.UTF_8));
-
}
-
/**
-
* A snapshot of the values for an entry.
-
*/
-
public final class Snapshot implements Closeable {
-
private final String key;
-
private final long sequenceNumber;
-
private final InputStream[] ins;
-
private Snapshot(String key, long sequenceNumber, InputStream[] ins) {
-
this.key = key;
-
this.sequenceNumber = sequenceNumber;
-
this.ins = ins;
-
}
-
/**
-
* Returns an editor for this snapshot’s entry, or null if either the
-
* entry has changed since this snapshot was created or if another edit
-
* is in progress.
-
*/
-
public Editor edit() throws IOException {
-
return DiskLruCache.this.edit(key, sequenceNumber);
-
}
-
/**
-
* Returns the unbuffered stream with the value for {@code index}.
-
*/
-
public InputStream getInputStream(int index) {
-
return ins[index];
-
}
-
/**
-
* Returns the string value for {@code index}.
-
*/
-
public String getString(int index) throws IOException {
-
return inputStreamToString(getInputStream(index));
-
}
-
@Override public void close() {
-
for (InputStream in : ins) {
-
IoUtils.closeQuietly(in);
-
}
-
}
-
}
-
/**
-
* Edits the values for an entry.
-
*/
-
public final class Editor {
-
private final Entry entry;
-
private boolean hasErrors;
-
private Editor(Entry entry) {
-
this.entry = entry;
-
}
-
/**
-
* Returns an unbuffered input stream to read the last committed value,
-
* or null if no value has been committed.
-
*/
-
public InputStream newInputStream(int index) throws IOException {
-
synchronized (DiskLruCache.this) {
-
if (entry.currentEditor != this) {
-
throw new IllegalStateException();
-
}
-
if (!entry.readable) {
-
return null;
-
}
-
return new FileInputStream(entry.getCleanFile(index));
-
}
-
}
-
/**
-
* Returns the last committed value as a string, or null if no value
-
* has been committed.
-
*/
-
public String getString(int index) throws IOException {
-
InputStream in = newInputStream(index);
-
return in != null ? inputStreamToString(in) : null;
-
}
-
/**
-
* Returns a new unbuffered output stream to write the value at
-
* {@code index}. If the underlying output stream encounters errors
-
* when writing to the filesystem, this edit will be aborted when
-
* {@link #commit} is called. The returned output stream does not throw
-
* IOExceptions.
-
*/
-
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)));
-
}
-
}
-
/**
-
* Sets the value at {@code index} to {@code value}.
-
*/
-
public void set(int index, String value) throws IOException {
-
Writer writer = null;
-
try {
-
writer = new OutputStreamWriter(newOutputStream(index), Charsets.UTF_8);
-
writer.write(value);
-
} finally {
-
IoUtils.closeQuietly(writer);
-
}
-
}
-
/**
-
* Commits this edit so it is visible to readers. This releases the
-
* edit lock so another edit may be started on the same key.
-
*/
-
public void commit() throws IOException {
-
if (hasErrors) {
-
completeEdit(this, false);
-
remove(entry.key); // the previous entry is stale
-
} else {
-
completeEdit(this, true);
-
}
-
}
-
/**
-
* Aborts this edit. This releases the edit lock so another edit may be
-
* started on the same key.
-
*/
-
public void abort() throws IOException {
-
completeEdit(this, false);
-
}
-
private class FaultHidingOutputStream extends FilterOutputStream {
-
private FaultHidingOutputStream(OutputStream out) {
-
super(out);
-
}
-
@Override public void write(int oneByte) {
-
try {
-
out.write(oneByte);
-
} catch (IOException e) {
-
hasErrors = true;
-
}
-
}
-
@Override public void write(byte[] buffer, int offset, int length) {
-
try {
-
out.write(buffer, offset, length);
-
} catch (IOException e) {
-
hasErrors = true;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
最后
代码真的是重质不重量,质量高的代码,是当前代码界提倡的,当然写出高质量的代码肯定需要一个相当高的专业素养,这需要在日常的代码书写中逐渐去吸收掌握,谁不是每天都在学习呀,目的还不是为了一个,为实现某个功能写出高质量的代码。
所以,长征路还长,大家还是好好地做个务实的程序员吧。
最后,小编这里有一系列Android提升学习资料,有兴趣的小伙伴们可以来看下哦~
completeEdit(this, false);
-
}
-
private class FaultHidingOutputStream extends FilterOutputStream {
-
private FaultHidingOutputStream(OutputStream out) {
-
super(out);
-
}
-
@Override public void write(int oneByte) {
-
try {
-
out.write(oneByte);
-
} catch (IOException e) {
-
hasErrors = true;
-
}
-
}
-
@Override public void write(byte[] buffer, int offset, int length) {
-
try {
-
out.write(buffer, offset, length);
-
} catch (IOException e) {
-
hasErrors = true;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-900vESPw-1712070700826)]
[外链图片转存中…(img-BNsFUaNa-1712070700827)]
[外链图片转存中…(img-ghxYW02e-1712070700827)]
[外链图片转存中…(img-l86SSqDE-1712070700827)]
[外链图片转存中…(img-I06OVIe0-1712070700828)]
[外链图片转存中…(img-oq9F2OH5-1712070700828)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-EdMaOXBB-1712070700828)]
最后
代码真的是重质不重量,质量高的代码,是当前代码界提倡的,当然写出高质量的代码肯定需要一个相当高的专业素养,这需要在日常的代码书写中逐渐去吸收掌握,谁不是每天都在学习呀,目的还不是为了一个,为实现某个功能写出高质量的代码。
所以,长征路还长,大家还是好好地做个务实的程序员吧。
最后,小编这里有一系列Android提升学习资料,有兴趣的小伙伴们可以来看下哦~