private Stream CacheAndCreateEntryStream(string filename, string entryName) { Stream stream = null; var dataStream = _dataProvider.Fetch(filename); if (dataStream != null) { try { var newItem = new CachedZipFile(dataStream, DateTime.UtcNow, filename); // here we don't need to lock over the cache item // because it was still not added in the cache stream = CreateEntryStream(newItem, entryName, filename); if (!_zipFileCache.TryAdd(filename, newItem)) { // some other thread could of added it already, lets dispose ours newItem.Dispose(); } } catch (Exception exception) { if (exception is ZipException || exception is ZlibException) { Log.Error("ZipDataCacheProvider.Fetch(): Corrupt zip file/entry: " + filename + "#" + entryName + " Error: " + exception); } else { throw; } } } return(stream); }
/// <summary> /// Create a stream of a specific ZipEntry /// </summary> /// <param name="zipFile">The zipFile containing the zipEntry</param> /// <param name="entryName">The name of the entry</param> /// <param name="fileName">The name of the zip file on disk</param> /// <returns>A <see cref="Stream"/> of the appropriate zip entry</returns> private Stream CreateEntryStream(CachedZipFile zipFile, string entryName, string fileName) { ZipEntryCache entryCache; if (entryName == null) { entryCache = zipFile.EntryCache.FirstOrDefault().Value; } else { zipFile.EntryCache.TryGetValue(entryName, out entryCache); } if (entryCache is { Modified : true })
/// <summary> /// Cache a Zip /// </summary> /// <param name="filename">Zip to cache</param> /// <param name="cachedZip">The resulting CachedZipFile</param> /// <returns></returns> private bool Cache(string filename, out CachedZipFile cachedZip) { cachedZip = null; var dataStream = _dataProvider.Fetch(filename); if (dataStream != null) { try { cachedZip = new CachedZipFile(dataStream, DateTime.UtcNow, filename); if (!_zipFileCache.TryAdd(filename, cachedZip)) { // some other thread could of added it already, lets dispose ours cachedZip.Dispose(); return(_zipFileCache.TryGetValue(filename, out cachedZip)); } return(true); } catch (Exception exception) { if (exception is ZipException || exception is ZlibException) { Log.Error("ZipDataCacheProvider.Fetch(): Corrupt zip file/entry: " + filename + " Error: " + exception); } else { throw; } } dataStream.Dispose(); } return(false); }
/// <summary> /// Does not attempt to retrieve any data /// </summary> public Stream Fetch(string key) { string entryName = null; // default to all entries var filename = key; var hashIndex = key.LastIndexOf("#", StringComparison.Ordinal); if (hashIndex != -1) { entryName = key.Substring(hashIndex + 1); filename = key.Substring(0, hashIndex); } // handles zip files if (filename.GetExtension() == ".zip") { Stream stream = null; // scan the cache once every 3 seconds if (_lastCacheScan == DateTime.MinValue || _lastCacheScan < DateTime.Now.AddSeconds(-3)) { CleanCache(); } try { CachedZipFile existingEntry; if (!_zipFileCache.TryGetValue(filename, out existingEntry)) { var dataStream = _dataProvider.Fetch(filename); if (dataStream != null) { try { var newItem = new CachedZipFile(dataStream, filename); stream = CreateStream(newItem, entryName, filename); if (!_zipFileCache.TryAdd(filename, newItem)) { newItem.Dispose(); } } catch (Exception exception) { if (exception is ZipException || exception is ZlibException) { Log.Error("ZipDataCacheProvider.Fetch(): Corrupt zip file/entry: " + filename + "#" + entryName + " Error: " + exception); } else { throw; } } } } else { try { lock (existingEntry) { stream = CreateStream(existingEntry, entryName, filename); } } catch (Exception exception) { if (exception is ZipException || exception is ZlibException) { Log.Error("ZipDataCacheProvider.Fetch(): Corrupt zip file/entry: " + filename + "#" + entryName + " Error: " + exception); } else { throw; } } } return(stream); } catch (Exception err) { Log.Error(err, "Inner try/catch"); stream?.DisposeSafely(); return(null); } } else { // handles text files return(_dataProvider.Fetch(filename)); } }
/// <summary> /// Create a stream of a specific ZipEntry /// </summary> /// <param name="zipFile">The zipFile containing the zipEntry</param> /// <param name="entryName">The name of the entry</param> /// <param name="fileName">The name of the zip file on disk</param> /// <returns>A <see cref="Stream"/> of the appropriate zip entry</returns> private Stream CreateStream(CachedZipFile zipFile, string entryName, string fileName) { ZipEntry entry; if (entryName == null) { entry = zipFile.EntryCache.FirstOrDefault().Value; } else { zipFile.EntryCache.TryGetValue(entryName, out entry); } if (entry != null) { var stream = new MemoryStream(); try { stream.SetLength(entry.UncompressedSize); } catch (ArgumentOutOfRangeException) { // The needed size of the MemoryStream is longer than allowed. // just read the data directly from the file. // Note that we cannot use entry.OpenReader() because only one OpenReader // can be open at a time without causing corruption. // We must use fileName instead of zipFile.Name, // because zipFile is initialized from a stream and not a file. var zipStream = new ZipInputStream(fileName); var zipEntry = zipStream.GetNextEntry(); // The zip file was empty! if (zipEntry == null) { return(null); } // Null entry name, return the first. if (entryName == null) { return(zipStream); } // Non-default entry name, return matching one if it exists, otherwise null. while (zipEntry != null) { if (string.Compare(zipEntry.FileName, entryName, StringComparison.OrdinalIgnoreCase) == 0) { return(zipStream); } zipEntry = zipStream.GetNextEntry(); } } entry.OpenReader().CopyTo(stream); stream.Position = 0; return(stream); } return(null); }
/// <summary> /// Does not attempt to retrieve any data /// </summary> public Stream Fetch(string key) { string entryName = null; // default to all entries var filename = key; var hashIndex = key.LastIndexOf("#", StringComparison.Ordinal); if (hashIndex != -1) { entryName = key.Substring(hashIndex + 1); filename = key.Substring(0, hashIndex); } // handles zip files if (filename.GetExtension() == ".zip") { Stream stream = null; // scan the cache once every 3 seconds if (_lastCacheScan == DateTime.MinValue || _lastCacheScan < DateTime.Now.AddSeconds(-3)) { CleanCache(); } try { var dataStream = _dataProvider.Fetch(filename); if (dataStream != null) { _zipFileCache.AddOrUpdate(filename, x => { var newItem = new CachedZipFile(ZipFile.Read(dataStream), filename); stream = CreateStream(newItem.ZipFile, entryName); return(newItem); }, (x, existingEntry) => { stream = CreateStream(existingEntry.ZipFile, entryName); return(existingEntry); }); //stream = CreateStream(ZipFile.Read(dataStream), entryName); } return(stream); } catch (Exception err) { Log.Error(err, "Inner try/catch"); if (stream != null) { stream.Dispose(); } return(null); } } else { // handles text files return(_dataProvider.Fetch(filename)); } }