//------------------------------------------------------------------------------ // 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 // 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 // CSDN博客:https://blog.csdn.net/qq_40374647 // 哔哩哔哩视频:https://space.bilibili.com/94253567 // Gitee源代码仓库:https://gitee.com/RRQM_Home // Github源代码仓库:https://github.com/RRQM // API首页:https://www.yuque.com/rrqm/touchsocket/index // 交流QQ群:234762506 // 感谢您的下载和使用 //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using TouchSocket.Resources; namespace TouchSocket.Core { /// /// 文件池。 /// //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] public static partial class FilePool { private static readonly object m_locker = new object(); private static readonly ConcurrentDictionary m_pathStorage = new ConcurrentDictionary(); private static readonly Timer m_timer; static FilePool() { m_timer = new Timer(OnTimer, null, 60000, 60000); } /// /// 获取所有的路径。 /// /// public static string[] GetAllPaths() { return m_pathStorage.Keys.ToArray(); } /// /// 加载文件为读取流 /// /// /// /// /// public static FileStorage GetFileStorageForRead(string path) { if (string.IsNullOrEmpty(path)) { throw new System.ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); } return GetFileStorageForRead(new FileInfo(path)); } /// /// 加载文件为读取流 /// /// /// /// public static FileStorage GetFileStorageForRead(FileInfo fileInfo) { if (m_pathStorage.TryGetValue(fileInfo.FullName, out FileStorage storage)) { if (storage.FileAccess != FileAccess.Read) { throw new Exception("该路径的文件已经被加载为仅写入模式。"); } Interlocked.Increment(ref storage.m_reference); return storage; } lock (m_locker) { storage = new FileStorage(fileInfo, FileAccess.Read); if (m_pathStorage.TryAdd(fileInfo.FullName, storage)) { Interlocked.Increment(ref storage.m_reference); return storage; } else { return GetFileStorageForRead(fileInfo); } } } /// /// 加载文件为写流 /// /// /// /// /// public static FileStorage GetFileStorageForWrite(string path) { if (string.IsNullOrEmpty(path)) { throw new ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); } return GetFileStorageForWrite(new FileInfo(path)); } /// /// 加载文件为写流 /// /// /// /// /// public static FileStorage GetFileStorageForWrite(FileInfo fileInfo) { if (m_pathStorage.TryGetValue(fileInfo.FullName, out FileStorage storage)) { if (storage.FileAccess != FileAccess.Write) { throw new Exception("该路径的文件已经被加载为仅读取模式。"); } Interlocked.Increment(ref storage.m_reference); return storage; } lock (m_locker) { storage = new FileStorage(fileInfo, FileAccess.Write); if (m_pathStorage.TryAdd(fileInfo.FullName, storage)) { Interlocked.Increment(ref storage.m_reference); return storage; } else { return GetFileStorageForWrite(fileInfo); } } } /// /// 获取一个可读可写的Stream对象。 /// /// /// /// /// public static FileStorageStream GetFileStorageStream(string path) { return new FileStorageStream(GetFileStorageForWrite(path)); } /// /// 获取一个可读可写的Stream对象。 /// /// /// /// /// public static FileStorageStream GetFileStorageStream(FileInfo fileInfo) { return new FileStorageStream(GetFileStorageForWrite(fileInfo)); } /// /// 获取一个文件读取访问器 /// /// /// /// /// public static FileStorageReader GetReader(string path) { return new FileStorageReader(GetFileStorageForRead(path)); } /// /// 获取一个文件读取访问器 /// /// /// /// /// public static FileStorageReader GetReader(FileInfo fileInfo) { return new FileStorageReader(GetFileStorageForRead(fileInfo)); } /// /// 获取引用次数。 /// /// 必须是全路径。 /// /// /// public static int GetReferenceCount(string path) { if (string.IsNullOrEmpty(path)) { return 0; } if (m_pathStorage.TryGetValue(path, out FileStorage fileStorage)) { return fileStorage.m_reference; } return 0; } /// /// 获取一个文件写入访问器 /// /// 路径 /// /// /// public static FileStorageWriter GetWriter(string path) { return new FileStorageWriter(GetFileStorageForWrite(path)); } /// /// 获取一个文件写入访问器 /// /// /// /// /// public static FileStorageWriter GetWriter(FileInfo fileInfo) { return new FileStorageWriter(GetFileStorageForWrite(fileInfo)); } /// /// 加载文件为缓存读取流 /// /// /// /// /// public static void LoadFileForCacheRead(string path) { if (string.IsNullOrEmpty(path)) { throw new System.ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); } path = Path.GetFullPath(path); if (m_pathStorage.TryGetValue(path, out FileStorage storage)) { if (storage.FileAccess != FileAccess.Read || !storage.Cache) { throw new Exception("该路径的文件已经被加载为其他模式。"); } return; } if (FileStorage.TryCreateCacheFileStorage(path, out FileStorage fileStorage, out string msg)) { m_pathStorage.TryAdd(path, fileStorage); } else { throw new Exception(msg); } } /// /// 减少引用次数,并尝试释放流。 /// /// /// 延迟释放时间。当设置为0时,立即释放,单位毫秒。 /// /// /// public static Result TryReleaseFile(string path, int delayTime = 0) { if (string.IsNullOrEmpty(path)) { return new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(path))); } path = Path.GetFullPath(path); if (m_pathStorage.TryGetValue(path, out FileStorage fileStorage)) { if (Interlocked.Decrement(ref fileStorage.m_reference) <= 0) { if (delayTime > 0) { EasyTask.DelayRun(delayTime, path, (p) => { if (GetReferenceCount(p) == 0) { if (m_pathStorage.TryRemove((string)p, out fileStorage)) { fileStorage.Dispose(); } } }); return new Result(ResultCode.Success, $"如果在{delayTime}ms后引用仍然为0的话,即被释放。"); } else { if (m_pathStorage.TryRemove(path, out fileStorage)) { fileStorage.Dispose(); } return new Result(ResultCode.Success, "流成功释放。"); } } else { return new Result(ResultCode.Error, TouchSocketStatus.StreamReferencing.GetDescription(path, fileStorage.m_reference)); } } else { return new Result(ResultCode.Success, TouchSocketStatus.StreamNotFind.GetDescription(path)); } } private static void OnTimer(object state) { var keys = new List(); foreach (KeyValuePair item in m_pathStorage) { if (DateTime.Now - item.Value.AccessTime > item.Value.AccessTimeout) { keys.Add(item.Key); } } foreach (string item in keys) { TryReleaseFile(item); } } } }