//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在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;
}
}
}
}