//------------------------------------------------------------------------------ // 此代码版权(除特别声明或在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.IO; using System.Threading; using TouchSocket.Resources; namespace TouchSocket.Core { /// /// 文件存储器。在该存储器中,读写线程安全。 /// //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] public partial class FileStorage { internal volatile int m_reference; private readonly ReaderWriterLockSlim m_lockSlim; private bool m_disposedValue; private byte[] m_fileData; /// /// 初始化一个文件存储器。在该存储器中,读写线程安全。 /// internal FileStorage(FileInfo fileInfo, FileAccess fileAccess) : this() { this.FileAccess = fileAccess; this.FileInfo = fileInfo; this.Path = fileInfo.FullName; this.m_reference = 0; this.FileStream = fileAccess == FileAccess.Read ? fileInfo.OpenRead() : fileInfo.OpenWrite(); this.m_lockSlim = new ReaderWriterLockSlim(); } private FileStorage() { this.AccessTime = DateTime.Now; this.AccessTimeout = TimeSpan.FromSeconds(60); } /// /// 最后访问时间。 /// public DateTime AccessTime { get; private set; } /// /// 访问超时时间。默认10s /// public TimeSpan AccessTimeout { get; set; } /// /// 是否为缓存型。为false时,意味着该文件句柄正在被该程序占用。 /// public bool Cache { get; private set; } /// /// 访问属性 /// public FileAccess FileAccess { get; private set; } /// /// 文件信息 /// public FileInfo FileInfo { get; private set; } /// /// 文件流。 /// 一般情况下,请不要直接访问该对象。否则有可能会产生不可预测的错误。 /// public FileStream FileStream { get; private set; } /// /// 文件长度 /// public long Length => this.FileStream.Length; /// /// 文件路径 /// public string Path { get; private set; } /// /// 引用次数。 /// public int Reference => this.m_reference; /// /// 创建一个只读的、已经缓存的文件信息。该操作不会占用文件句柄。 /// /// /// /// /// public static bool TryCreateCacheFileStorage(string path, out FileStorage fileStorage, out string msg) { path = System.IO.Path.GetFullPath(path); if (!File.Exists(path)) { fileStorage = null; msg = TouchSocketStatus.FileNotExists.GetDescription(path); return false; } try { fileStorage = new FileStorage() { Cache = true, FileAccess = FileAccess.Read, FileInfo = new FileInfo(path), Path = path, m_reference = 0, m_fileData = File.ReadAllBytes(path) }; msg = null; return true; } catch (Exception ex) { fileStorage = null; msg = ex.Message; return false; } } /// /// 写入时清空缓存区 /// public void Flush() { this.AccessTime = DateTime.Now; this.FileStream.Flush(); } /// /// 从指定位置,读取数据到缓存区。线程安全。 /// /// /// /// /// /// public int Read(long stratPos, byte[] buffer, int offset, int length) { this.AccessTime = DateTime.Now; using (var writeLock = new WriteLock(this.m_lockSlim)) { if (this.m_disposedValue) { throw new ObjectDisposedException(this.GetType().FullName); } if (this.FileAccess == FileAccess.Write) { throw new Exception("该流不允许读取。"); } if (this.Cache) { int r = (int)Math.Min(this.m_fileData.Length - stratPos, length); Array.Copy(this.m_fileData, stratPos, buffer, offset, r); return r; } else { this.FileStream.Position = stratPos; return this.FileStream.Read(buffer, offset, length); } } } /// /// 减少引用次数,并尝试释放流。 /// /// 延迟释放时间。当设置为0时,立即释放,单位毫秒。 /// /// /// public Result TryReleaseFile(int delayTime = 0) { return FilePool.TryReleaseFile(this.Path, delayTime); } /// /// 从指定位置,写入数据到存储区。线程安全。 /// /// /// /// /// public void Write(long stratPos, byte[] buffer, int offset, int length) { this.AccessTime = DateTime.Now; using (var writeLock = new WriteLock(this.m_lockSlim)) { if (this.m_disposedValue) { throw new ObjectDisposedException(this.GetType().FullName); } if (this.FileAccess == FileAccess.Read) { throw new Exception("该流不允许写入。"); } this.FileStream.Position = stratPos; this.FileStream.Write(buffer, offset, length); } } internal void Dispose() { if (this.m_disposedValue) { return; } using (var writeLock = new WriteLock(this.m_lockSlim)) { this.m_disposedValue = true; this.FileStream.SafeDispose(); this.m_fileData = null; } } } }