首页 找课程 找学校 教育新闻 培训问答 课程大全

苏州其然软件开发培训

13013833891 预约试听 在线客服

您的位置: 首页 > 苏州培训 > 苏州其然软件开发培训 > web前端培训 > 张家港java软件技术培训

张家港java软件技术培训

班制:

周末班

[ 开班提醒 ]
上课地址:

苏州其然软件开发

活动倒计时
11: 59: 59
马上抢

课程介绍

张家港java软件技术培训
其然IT 教育师资

韩奇峰高级讲师

多年实战工作经验曾参与制作宝马Usage Training项目、DMS项目,奥迪全 息投影项目,奔驰等多家汽车门户行业大型项目,负责UI设计、界面设计、3D模型制作、前端开发等职务。

从事设计行业多年,精通PhotoShop、UI设计、AfterEffects、Flash、 Actionscript、HTML、CSS、JavaScript、jQuery、资深动画设计师,设计作品曾获得全国动画设计三等奖。

课程讲解注重实战应用,对讲述知识点穿插案例制作,使课程内容更加接近 工作中实际的项目。授课风格注重实战经验分析,深受学生喜欢。

张家港java软件技术培训

Java培训Java与自学Java的差距

张家港java软件技术培训

培训Java与自学Java的差距

我以前也是自学Java,在一家公司跟着别人学,以前是别人眼中的菜鸟,现 在是别人眼中的大神,Java很简单的,贵在坚持和多练,没必要花那培训钱。如果真的要去学的话,

选择Java培训机构要注意这两点基本上就能避免一些坑:

1. 老师没有正经公司工作经历,或者没有已经在线上正常运转的产品。一 些所谓培训班的老师水平往往比较一般,甚至还有培训出来后又接着培训别人的。

2、是不是会承诺帮你找到工作,要找到好的工作,不是靠别人给你保证的 ,还是要靠自己提升能力。

建议多自己学习加上找些好的代码主动学习。例如github,多练习网上很多 网站里真正好的代码。作为Java工程师,可以多看看spring文档,看看很多已经成熟的框架,深入去体会。另外,学软件等等**好还是自己多学,找点 视频教程之类,也省点钱。

Java开发体系结构介绍

张家港java软件技术培训

Java开发体系结构介绍

1、类加载器:为程序的执行加载所需要的全部类。类加载器将本地文件系 统的类名空间与来自远程网络源的类名空间相分离,本地类总是首先被加载,以增加安全性。当全部类被加载后,可执行文件的存储器格式被确定。这 时,特定的存储器地址被分配给符号引用并创建检索表格。由于存储器格式在运行时出现,因而Java解释器增加了保护以防止对限制代码区的非法进入 。

2、字节代码校验器:基于代码的规范包括语法语义的检查以及如上所述的 安全性检查。

3、Java运行时解释器:它是JVM的核心内容,实现把抽象的字节码指令映射 到本地系统平台下的库引用或指令。

4、API类库:实现标准Java平台API的一系列可执行代码。

5、硬件本地平台接口:提供对底层系统平台资源库调用的接口。

DiskLruCache源码分析


>

简介

上篇文章介绍了LRUCache它的思想是把一部分常用的对象存在内存里,以便下次使用的时候快速提取。 但是内存容量也就三G两G的,早期的或者低端一点的也就几百M,能分给自己的APP用来缓存数据的空间实在不多。 但是别忘了,我们还有Disk这个后花园。磁盘缓存的速度虽然不然不及内存缓存,但是容量很大,是典型的用时间换空间思想。

简单使用

DiskLruCache mDiskLruCache = DiskLruCache.open(directory, appVersion, valueCount, maxSize); String key = generateKey(url); DiskLruCache.Editor editor = mDiskLruCache.edit(key); OuputStream os = editor.newOutputStream(0); DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); if (snapShot != null) { InputStream is = snapShot.getInputStream(0); }

valueCount 是每一个key对应的value文件有几个

Journal文件

Journal是一个日志文件,一个典型的Journal文件如下:

libcore.io.DiskLruCache 1 100 2

CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 DIRTY 335c4c6028171cfddfbaae1a9c313c52 CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 REMOVE 335c4c6028171cfddfbaae1a9c313c52 DIRTY 1ab96a171faeeee38496d8b330771a7a CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 READ 335c4c6028171cfddfbaae1a9c313c52 READ 3400330d1dfc7f3f7f4b8d4d803dfcf6

前五行组成了日志文件的文件头

**行 固定字符串libcore.io.DiskLruCache,也就是文件的魔数。 第二行 是DiskLruCache的版本号,源码中为常量1 第三行 是app的版本号,自己在open方法里传入 第四行 valueCount,每个key对应几个缓存文件 第五行 空行

接下来看起来乱乱的就是一条条操作记录了, 每一行由状态、key、如果key对应多个缓存文件且它是CLEAN的会依次列出缓存文件的大小。

DIRTY表示这个entry正在被写入,如果写入成功后边会跟一条CLEAN记录。 如果写入失败,后边会跟一条REMOVE记录。 CLEAN 表示缓存写好了,后边还会跟多个缓存文件的长度 READ get方法get一次,也就是读取一次,就写一个READ REMOVE 删除之后写

数据结构

lruEntries里存储了key和Entry,Entry里存储了关于文件的信息。 key和文件的状态存储在日志文件里,和日志文件同级的的真正缓存的文件。 这样lruEntries放在内存里,存储所有关于缓存的信息,同LRUCache一样,它也是LinkHashMap 所以也实现了LRU算法,在达到内存上限之后,删除掉近期**少使用的文件。

open

public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) throws IOException { // If a bkp file exists, use it instead. File backupFile = new File(directory, JOURNAL_FILE_BACKUP); if (backupFile.exists()) { File journalFile = new File(directory, JOURNAL_FILE); // If journal file also exists just delete backup file. if (journalFile.exists()) { backupFile.delete(); } else { renameTo(backupFile, journalFile, false); } } // PRefer to pick up where we left off. DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); if (cache.journalFile.exists()) { try { cache.readJournal(); cache.processJournal(); return cache; } catch (IOException journalIsCorrupt) { cache.delete(); } } // Create a new empty cache. directory.mkdirs(); cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); cache.rebuildJournal(); return cache; }

如果journal的备份文件已经存在,就去new一个journal文件,如果journal文件也已经存在,那么就删除备份, 如果journal文件不存在,那么就将备份文件变成journal文件,也就是重命名。

如果journal的备份文件不存在,那么说明该路径没有任何缓存,那么就创建一个空的cache,并调用rebuildJournal方法

rebuildJournal方法

private synchronized void rebuildJournal() throws IOException { if (journalWriter != null) { journalWriter.close(); } Writer writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII)); try { 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 ); } } } finally { writer.close(); } if (journalFile.exists()) { renameTo(journalFile, journalFileBackup, true); } renameTo(journalFileTmp, journalFile, false); journalFileBackup.delete(); journalWriter = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII)); }

创建journalFileTmp文件,并将其前5行写好。遍历lruEntries并将Entry当前的状态写入日志文件。 如果journalFile已经存在,那么就做个备份。 并将刚才的临时日志文件journalFileTmp重命名为日志文件journalFile。 然后删除备份日志文件。 为什么这么做呢?

readJournal

如果journalFile存在,那么首先调用了readJournal方法

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 we ended on a truncated line, rebuild the journal before appending to it. 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( ); if (firstSpace == -1) { throw new IOException("unexpected journal line: " line); } int keyBegin = firstSpace 1; int secondSpace = line.indexOf( , keyBegin); final String key; if (secondSpace == -1) { key = line.substring(keyBegin); 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 = new Entry(key); lruEntries.put(key, entry); } if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) { 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)) { entry.currentEditor = new Editor(entry); } else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) { // This work was already done by calling lruEntries.get(). } else { throw new IOException("unexpected journal line: " line); } }

进来之后首先校验文件格式对不对,也就是验证是不是标准的日志文件。 然后调用了readJournalLine方法,我们分析过日志文件它确实是每个记录单独一行。 首先从日志文件中把key读出来。 如果当前key对应的记录是REMOVE,那么就从lruEntries中remove掉。 如果lruEntries中还没有此条记录,那么就new一个Entry放进去。 如果是CLEAN状态,说明没有对象在操作这条记录。 如果是DIRTY状态,说明正在被编辑,那么给它赋值一个编辑器。 如果是READ状态,那么什么都不操作。 这样内存中的lruEntries就整体把控了当前缓存的情况。

**后,读取过程中如果发现journal文件有问题,则重建journal文件。 没有问题的话,初始化journalWriter,并关闭reader。

然后在open方法中又调用了processJournal方法

经过以上调用,之后journal文件、lruEntries、以及size就都初始化好了。

写入缓存

一开始的时候写缓存是这样调用的

String key = generateKey(url); DiskLruCache.Editor editor = mDiskLruCache.edit(key); OuputStream os = editor.newOutputStream(0);

也就是先调用了edit方法

edit

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

首先检查journalWriter有没有关闭以及key字符的合法性 然后去lruEntries里查找key对应的Entry,如果有就直接使用,如果没有就new一个。 然后new一个Editor给这个Entry 并在日志文件中写入DIRTY标志,标识此Entry正在被编辑。 **后返回这个Editor

然后调用了Editor的newOutputStream方法,拿到一个输出流。

newOutputStream

public OutputStream newOutputStream(int index) throws IOException { if (index < 0 || index >= valueCount) { throw new IllegalArgumentException("Expected index " index " to " "be greater than 0 and less than the maximum value count " "of " valueCount); } synchronized (DiskLruCache.this) { if (entry.currentEditor != this) { throw new IllegalStateException(); } if (!entry.readable) { written[index] = true; } File dirtyFile = entry.getDirtyFile(index); FileOutputStream outputStream; try { outputStream = new FileOutputStream(dirtyFile); } catch (FileNotFoundException e) { // Attempt to recreate the cache directory. directory.mkdirs(); try { outputStream = new FileOutputStream(dirtyFile); } catch (FileNotFoundException e2) { // We are unable to recover. Silently eat the writes. return NULL_OUTPUT_STREAM; } } return new FaultHidingOutputStream(outputStream); } }

创建一个输出流,并将流写入dirtyFile这个临时文件里。 dirtyFile**Entry的getDirtyFile创建,它的命名规则是key.index.tmp **输出流写完文件之后,调用commit方法。

commit

public void commit() throws IOException { if (hasErrors) { completeEdit(this, false); remove(entry.key); // The previous entry is stale. } else { completeEdit(this, true); } committed = true; }

completeEdit

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 (!editor.written[i]) { editor.abort(); throw new IllegalStateException("Newly created entry didn t create value for index " i); } if (!entry.getDirtyFile(i).exists()) { editor.abort(); return; } } } 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 ); } journalWriter.flush(); if (size > maxSize || journalRebuildRequired()) { executorService.submit(cleanupCallable); } }

如果成功 把dirtyFile变成cleanFile,并重新计算size。 然后把这个entry设置为可读,并写入一条CLEAN的操作日志。 如果失败 就把dirtyFile删除,然后把它从lruEntries中移除,并写入一条REMOVE的操作日志。 这样entry文件写好了,日志也写好了,这次缓存也就做好了。

读取

DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); if (snapShot != null) { InputStream is = snapShot.getInputStream(0); }

那么首先看get方法

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! for (int i = 0; i < valueCount; i ) { if (ins[i] != null) { Util.closeQuietly(ins[i]); } else { break; } } return null; } redundantOpCount ; journalWriter.append(READ key \n ); if (journalRebuildRequired()) { executorService.submit(cleanupCallable); } return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths); }

同样是检查journalWriter有没有关闭,以及key的合法性。 然后new出valueCount个输入流。 向日志文件中写入一条READ日志。 **后封装一个Snapshot返回 拿到输入流,就可以读入文件了。


相关推荐:


苏州JAVA培训   苏州JAVA培训班   苏州JAVA培训机构

倒计时
11: 59: 19
课程热线:13013833891 | 客服时间:9:00-22:00(其他时间请在线预约报名或留言)
机构介绍
其然软件是一所专业从事程序编程语言开发培训的机构,我们开设有JAVA、.NET、C/C++,WEB前端等课程,其中JAVA为其然软件的核心课程,从2011年至今已为江浙沪培养一批又一批的专业型软件技术开发人才,每一期学员的就业l都在80%以上,我们有科学的课程体系,人性化的学习管理,努力为昆山地区的软件事业贡献出自己的一份力量。 做朴实的软件开发培训是其然软件的宗旨,朴素而...【详情】
相关课程
其他城市
相关机构

申请试听名额

已有10254人申请免费试听

01电话咨询 | 13013833891

QQ:1413838287
加盟合作:0755-83654572