MainApplication的构造函数599行实例化了worldWindow的Cache属性。
// set Upper and Lower limits for Cache size control, in bytes long CacheUpperLimit = (long)Settings.CacheSizeMegaBytes * 1024L * 1024L; long CacheLowerLimit = (long)Settings.CacheSizeMegaBytes * 768L * 1024L; //75% of upper limit //Set up the cache worldWindow.Cache = new Cache( Settings.CachePath, CacheLowerLimit, CacheUpperLimit, Settings.CacheCleanupInterval, Settings.TotalRunTime );
这之前先看一下432行Settings的定义,
public static WorldWindSettings Settings = new WorldWindSettings();
在487~501行Main函数中可以看到通过LoadSettings()函数实现settings的赋值。
// ParseArgs may set values that are used elsewhere, // such as startFullScreen and CurrentSettingsDirectory. ParseArgs(args); if(CurrentSettingsDirectory == null) { // load program settings from default directory LoadSettings(); World.LoadSettings(); } else { LoadSettings(CurrentSettingsDirectory); World.LoadSettings(CurrentSettingsDirectory); }
1 /// <summary> 2 /// Deserializes and optionally decrypts settings 3 /// </summary> 4 private static void LoadSettings() 5 { 6 try 7 { 8 Settings = (WorldWindSettings) SettingsBase.Load(Settings, SettingsBase.LocationType.User); 9 10 if(!File.Exists(Settings.FileName)) 11 { 12 Settings.PluginsLoadedOnStartup.Add("ShapeFileInfoTool"); 13 //Settings.PluginsLoadedOnStartup.Add("OverviewFormLoader"); 14 //Settings.PluginsLoadedOnStartup.Add("Atmosphere"); 15 Settings.PluginsLoadedOnStartup.Add("SkyGradient"); 16 Settings.PluginsLoadedOnStartup.Add("BmngLoader"); 17 //Settings.PluginsLoadedOnStartup.Add("Compass"); 18 //Settings.PluginsLoadedOnStartup.Add("ExternalLayerManagerLoader"); 19 Settings.PluginsLoadedOnStartup.Add("MeasureTool"); 20 //Settings.PluginsLoadedOnStartup.Add("MovieRecorder"); 21 Settings.PluginsLoadedOnStartup.Add("NRLWeatherLoader"); 22 Settings.PluginsLoadedOnStartup.Add("ShapeFileLoader"); 23 Settings.PluginsLoadedOnStartup.Add("Stars3D"); 24 Settings.PluginsLoadedOnStartup.Add("GlobalClouds"); 25 Settings.PluginsLoadedOnStartup.Add("PlaceFinderLoader"); 26 Settings.PluginsLoadedOnStartup.Add("LightController"); 27 28 Settings.PluginsLoadedOnStartup.Add("Earthquake_2.0.2.1"); 29 Settings.PluginsLoadedOnStartup.Add("Historical_Earthquake_2.0.2.2"); 30 Settings.PluginsLoadedOnStartup.Add("KMLImporter"); 31 //Settings.PluginsLoadedOnStartup.Add("doublezoom"); 32 //Settings.PluginsLoadedOnStartup.Add("PlanetaryRings"); 33 Settings.PluginsLoadedOnStartup.Add("TimeController"); 34 //Settings.PluginsLoadedOnStartup.Add("WavingFlags"); 35 Settings.PluginsLoadedOnStartup.Add("ScaleBarLegend"); 36 Settings.PluginsLoadedOnStartup.Add("Compass3D"); 37 Settings.PluginsLoadedOnStartup.Add("AnaglyphStereo"); 38 Settings.PluginsLoadedOnStartup.Add("GlobeIcon"); 39 40 } 41 // decrypt encoded user credentials 42 DataProtector dp = new DataProtector(DataProtector.Store.USE_USER_STORE); 43 44 if(Settings.ProxyUsername.Length > 0) Settings.ProxyUsername = dp.TransparentDecrypt(Settings.ProxyUsername); 45 if(Settings.ProxyPassword.Length > 0) Settings.ProxyPassword = dp.TransparentDecrypt(Settings.ProxyPassword); 46 } 47 catch(Exception caught) 48 { 49 Log.Write(caught); 50 } 51 }
Settings = (WorldWindSettings) SettingsBase.Load(Settings, SettingsBase.LocationType.User);这句代码需要详细查看, SettingsBase.LocationType.User
1 public static string DefaultLocation(LocationType locationType) 2 { 3 string directory; 4 5 switch(locationType) 6 { 7 case LocationType.UserLocal: 8 // Example: @"C:\Documents and Settings\<user>\Local Settings\Application Data\NASA\NASA World Wind\1.3.3.11250" 9 return Application.LocalUserAppDataPath; 10 11 case LocationType.UserCommon: 12 // Example: @"C:\Documents and Settings\All Users\Application Data\NASA\NASA World Wind\1.3.3.11250" 13 return Application.CommonAppDataPath; 14 15 case LocationType.Application: 16 // Example: @"C:\Program Files\NASA\World Wind\" 17 return Application.StartupPath; 18 19 default: 20 // fall through to regular (roaming) user 21 case LocationType.User: 22 // Example: @"C:\Documents and Settings\<user>\Application Data\NASA\World Wind\1.3.3" 23 directory = Log.DefaultSettingsDirectory(); 24 Directory.CreateDirectory(directory); 25 return directory; 26 } 27 }
设置断点会发现directory的路径为:‘C:\Users\yangfan\AppData\Roaming\NASA\World Wind\1.4.0.0’,进入一看,原来是日志文件和World、WorldWind配置文件。
我还以为是影像或者矢量数据的缓存呢!
SettingsBase利用XmlSerializer实现配置文件保存。
MainApplication中只有开始介绍的一句实例化了worldWindow的Cache属性,而WorldWindow类中也只有private Cache m_Cache;属性定义。
注意到Cache类中定义了对象:Timer m_timer;
1 /// <summary> 2 /// Initializes a new instance of the <see cref= "T:WorldWind.Cache"/> class. 3 /// </summary> 4 /// <param name="cacheDirectory">Location of the cache files.</param> 5 /// <param name="cleanupFrequencyInterval">Frequency of cache cleanup.</param> 6 /// <param name="totalRunTime">Total duration application has been running so far.</param> 7 public Cache( 8 string cacheDirectory, 9 TimeSpan cleanupFrequencyInterval, 10 TimeSpan totalRunTime) 11 { 12 this.CleanupFrequency = cleanupFrequencyInterval; 13 this.CacheDirectory = cacheDirectory; 14 Directory.CreateDirectory(this.CacheDirectory); 15 16 // Start the timer 17 double firstDueSeconds = cleanupFrequencyInterval.TotalSeconds - 18 totalRunTime.TotalSeconds % cleanupFrequencyInterval.TotalSeconds; 19 m_timer = new Timer( new TimerCallback(OnTimer), null, 20 (long)(firstDueSeconds*1000), 21 (long)cleanupFrequencyInterval.TotalMilliseconds ); 22 } 23 24 /// <summary> 25 /// Constructor. 26 /// </summary> 27 /// <param name="cacheDirectory">Location of the cache files.</param> 28 /// <param name="cleanupFrequencyInterval">Frequency of cache cleanup.</param> 29 /// <param name="totalRunTime">Total duration application has been running so far.</param> 30 public Cache( 31 string cacheDirectory, 32 long cacheLowerLimit, 33 long cacheUpperLimit, 34 TimeSpan cleanupFrequencyInterval, 35 TimeSpan totalRunTime) 36 : this(cacheDirectory, cleanupFrequencyInterval, totalRunTime ) 37 { 38 this.CacheLowerLimit = cacheLowerLimit; 39 this.CacheUpperLimit = cacheUpperLimit; 40 }
延迟后,每间隔cleanupFrequencyInterval.TotalMilliseconds调用OnTimer方法执行清理。
1 /// <summary> 2 /// Monitors the cache, makes sure it stays within limits. 3 /// </summary> 4 private void OnTimer(object state) 5 { 6 try 7 { 8 // We are are not in a hurry 9 Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; 10 11 // dirSize is reported as the total of the file sizes, in bytes 12 // TODO: use the on-disk filesize, not FileInfo.Length, to calculate dirSize 13 long dirSize = GetDirectorySize(new DirectoryInfo(this.CacheDirectory));//dirSize是缓存文件夹的大小 14 if(dirSize < this.CacheUpperLimit)//小于限定值不清理 15 return; 16 17 ArrayList fileInfoList = GetDirectoryFileInfoList(new DirectoryInfo(this.CacheDirectory)); 18 while(dirSize > this.CacheLowerLimit) 19 { 20 if (fileInfoList.Count <= 100) 21 break; 22 23 FileInfo oldestFile = null; 24 foreach(FileInfo curFile in fileInfoList) 25 { 26 if(oldestFile == null) 27 { 28 oldestFile = curFile; 29 continue; 30 } 31 32 if(curFile.LastAccessTimeUtc < oldestFile.LastAccessTimeUtc) 33 { 34 oldestFile = curFile; 35 } 36 } 37 38 fileInfoList.Remove(oldestFile); 39 dirSize -= oldestFile.Length; 40 try 41 { 42 File.Delete(oldestFile.FullName); 43 44 // Recursively remove empty directories 45 string directory = oldestFile.Directory.FullName; 46 while(Directory.GetFileSystemEntries(directory).Length==0) 47 { 48 Directory.Delete(directory); 49 directory = Path.GetDirectoryName(directory); 50 } 51 } 52 catch(IOException) 53 { 54 // Ignore non-removable file - move on to next 55 } 56 } 57 } 58 catch(Exception caught) 59 { 60 Log.Write(Log.Levels.Error, "CACH", caught.Message); 61 } 62 }
计算缓存文件夹大小:
1 public static long GetDirectorySize(DirectoryInfo inDir) 2 { 3 long returnBytes = 0; 4 foreach(DirectoryInfo subDir in inDir.GetDirectories()) 5 { 6 returnBytes += GetDirectorySize(subDir); 7 } 8 foreach(FileInfo fi in inDir.GetFiles()) 9 { 10 try 11 { 12 returnBytes += fi.Length; 13 } 14 catch(System.IO.IOException) 15 { 16 // Ignore files that may have disappeared since we started scanning. 17 } 18 } 19 return returnBytes; 20 }