发布:4.0.0

This commit is contained in:
若汝棋茗
2025-11-23 12:38:05 +08:00
parent ac7e87affb
commit 4a388134db
14 changed files with 524 additions and 757 deletions

View File

@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<BaseVersion>4.0.0-rc.50</BaseVersion>
<BaseVersion>4.0.0</BaseVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">

View File

@@ -988,20 +988,6 @@ public static class SystemExtension
/// <exception cref="IOException">当读取的字节数与流的长度不匹配时抛出。</exception>
public static byte[] ReadAllToByteArray(this Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream), "输入的 Stream 不能为 null。");
}
// 如果流支持长度属性,并且流的位置在起始位置,可以直接创建对应长度的数组
if (stream.CanSeek && stream.Length > 0 && stream.Position == 0)
{
var buffer = new byte[stream.Length];
var bytesRead = stream.Read(buffer, 0, buffer.Length);
return bytesRead != buffer.Length ? throw new IOException("读取的字节数与流的长度不匹配。") : buffer;
}
// 如果流不支持长度属性或位置不在起始位置,使用 MemoryStream 来读取数据
using (var memoryStream = new MemoryStream())
{
var buffer = new byte[4096];
@@ -1013,6 +999,20 @@ public static class SystemExtension
return memoryStream.ToArray();
}
}
public static async Task<byte[]> ReadAllToByteArrayAsync(this Stream stream, CancellationToken cancellationToken)
{
using (var memoryStream = new MemoryStream())
{
var buffer = new byte[4096];
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, cancellationToken)) > 0)
{
memoryStream.Write(buffer, 0, bytesRead);
}
return memoryStream.ToArray();
}
}
#endregion
#region IEnumerable

View File

@@ -11,283 +11,54 @@
//------------------------------------------------------------------------------
using System.Collections.Concurrent;
using TouchSocket.Resources;
namespace TouchSocket.Core;
/// <summary>
/// 文件池
/// 文件池
/// </summary>
public static partial class FilePool
{
private static readonly Lock s_locker = new Lock();
private static readonly ConcurrentDictionary<string, FileStorage> s_storages = new ConcurrentDictionary<string, FileStorage>();
private static readonly ConcurrentDictionary<string, FileStorage> m_pathStorage = new ConcurrentDictionary<string, FileStorage>();
private static readonly Timer s_timer;
static FilePool()
/// <summary>
/// 获取文件存储器
/// </summary>
/// <param name="path">文件路径</param>
/// <returns>文件存储器</returns>
public static FileStorage GetStorage(string path)
{
s_timer = new Timer(OnTimer, null, 1000 * 60, 1000 * 60);
ThrowHelper.ThrowArgumentNullExceptionIfStringIsNullOrEmpty(path, nameof(path));
var fullPath = Path.GetFullPath(path);
var storage = s_storages.GetOrAdd(fullPath, p => new FileStorage(p));
Interlocked.Increment(ref storage.m_referenceCount);
return storage;
}
/// <summary>
/// 获取所有的路径。
/// 获取文件流
/// </summary>
/// <returns></returns>
public static IEnumerable<string> GetAllPaths()
/// <param name="path">文件路径</param>
/// <returns>文件流</returns>
public static Stream GetStream(string path)
{
return m_pathStorage.Keys;
var storage = GetStorage(path);
return new FileStorageStream(storage);
}
private static void ThrowIfPathIsNull(string path)
/// <summary>
/// 释放文件
/// </summary>
/// <param name="storage">文件存储器</param>
internal static void ReleaseFile(FileStorage storage)
{
if (string.IsNullOrEmpty(path))
if (Interlocked.Decrement(ref storage.m_referenceCount) <= 0)
{
ThrowHelper.ThrowArgumentNullException(nameof(path));
}
}
/// <summary>
/// 加载文件为读取流
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorage GetFileStorageForRead(string path)
{
ThrowIfPathIsNull(path);
return GetFileStorageForRead(new FileInfo(path));
}
/// <summary>
/// 加载文件为读取流
/// </summary>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorage GetFileStorageForRead(FileInfo fileInfo)
{
if (m_pathStorage.TryGetValue(fileInfo.FullName, out var storage))
{
if (storage.FileAccess != FileAccess.Read)
if (s_storages.TryRemove(storage.Path, out _))
{
ThrowHelper.ThrowException(TouchSocketCoreResource.FileOnlyWrittenTo.Format(fileInfo.FullName));
}
Interlocked.Increment(ref storage.m_reference);
return storage;
}
lock (s_locker)
{
storage = new FileStorage(fileInfo, FileAccess.Read);
if (m_pathStorage.TryAdd(fileInfo.FullName, storage))
{
Interlocked.Increment(ref storage.m_reference);
return storage;
}
return GetFileStorageForRead(fileInfo);
}
}
/// <summary>
/// 加载文件为写流
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorage GetFileStorageForWrite(string path)
{
ThrowIfPathIsNull(path);
return GetFileStorageForWrite(new FileInfo(path));
}
/// <summary>
/// 加载文件为写流
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorage GetFileStorageForWrite(FileInfo fileInfo)
{
if (m_pathStorage.TryGetValue(fileInfo.FullName, out var storage))
{
if (storage.FileAccess != FileAccess.Write)
{
ThrowHelper.ThrowException(TouchSocketCoreResource.FileReadOnly.Format(fileInfo.FullName));
}
Interlocked.Increment(ref storage.m_reference);
return storage;
}
lock (s_locker)
{
storage = new FileStorage(fileInfo, FileAccess.Write);
if (m_pathStorage.TryAdd(fileInfo.FullName, storage))
{
Interlocked.Increment(ref storage.m_reference);
return storage;
}
return GetFileStorageForWrite(fileInfo);
}
}
/// <summary>
/// 获取一个可读可写的Stream对象。
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorageStream GetFileStorageStream(string path)
{
return new FileStorageStream(GetFileStorageForWrite(path));
}
/// <summary>
/// 获取一个可读可写的Stream对象。
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorageStream GetFileStorageStream(FileInfo fileInfo)
{
return new FileStorageStream(GetFileStorageForWrite(fileInfo));
}
/// <summary>
/// 获取一个文件读取访问器
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorageReader GetReader(string path)
{
return new FileStorageReader(GetFileStorageForRead(path));
}
/// <summary>
/// 获取一个文件读取访问器
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorageReader GetReader(FileInfo fileInfo)
{
return new FileStorageReader(GetFileStorageForRead(fileInfo));
}
/// <summary>
/// 获取引用次数。
/// </summary>
/// <param name="path">必须是全路径。</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static int GetReferenceCount(string path)
{
ThrowIfPathIsNull(path);
return m_pathStorage.TryGetValue(path, out var fileStorage) ? fileStorage.m_reference : 0;
}
/// <summary>
/// 获取一个文件写入访问器
/// </summary>
/// <param name="path">路径</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorageWriter GetWriter(string path)
{
return new FileStorageWriter(GetFileStorageForWrite(path));
}
/// <summary>
/// 获取一个文件写入访问器
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static FileStorageWriter GetWriter(FileInfo fileInfo)
{
return new FileStorageWriter(GetFileStorageForWrite(fileInfo));
}
private static void DelayRunReleaseFile(string path, int time)
{
_ = EasyTask.SafeRun(async () =>
{
await Task.Delay(time).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
if (GetReferenceCount(path) == 0)
{
if (m_pathStorage.TryRemove(path, out var fileStorage))
{
fileStorage.Dispose();
}
}
});
}
/// <summary>
/// 减少引用次数,并尝试释放流。
/// </summary>
/// <param name="path"></param>
/// <param name="delayTime">延迟释放时间。当设置为0时立即释放,单位毫秒。</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public static Result TryReleaseFile(string path, int delayTime = 0)
{
ThrowIfPathIsNull(path);
path = Path.GetFullPath(path);
if (m_pathStorage.TryGetValue(path, out var fileStorage))
{
if (Interlocked.Decrement(ref fileStorage.m_reference) <= 0)
{
if (delayTime > 0)
{
DelayRunReleaseFile(path, delayTime);
return new Result(ResultCode.Success);
}
else
{
if (m_pathStorage.TryRemove(path, out fileStorage))
{
fileStorage.Dispose();
}
return new Result(ResultCode.Success);
}
}
else
{
return new Result(ResultCode.Error, TouchSocketCoreResource.StreamReferencing.Format(path, fileStorage.m_reference));
storage.DisposeInternal();
}
}
else
{
return new Result(ResultCode.Success, TouchSocketCoreResource.StreamNotFind.Format(path));
}
}
private static void OnTimer(object state)
{
var keys = new List<string>();
foreach (var item in m_pathStorage)
{
if (DateTimeOffset.UtcNow - item.Value.AccessTime > item.Value.AccessTimeout)
{
keys.Add(item.Key);
}
}
foreach (var item in keys)
{
TryReleaseFile(item);
}
}
}
}

View File

@@ -9,178 +9,283 @@
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
using TouchSocket.Resources;
namespace TouchSocket.Core;
/// <summary>
/// 文件存储器。在该存储器中,读写线程安全。
/// 简化版文件存储器
/// </summary>
public partial class FileStorage
public sealed partial class FileStorage : IDisposable
{
internal volatile int m_reference;
private readonly ReaderWriterLockSlim m_lockSlim;
private bool m_disposedValue;
private readonly FileStream m_fileStream;
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
internal int m_referenceCount;
private bool m_disposed;
/// <summary>
/// 初始化一个文件存储器。在该存储器中,读写线程安全。
/// </summary>
internal FileStorage(FileInfo fileInfo, FileAccess fileAccess) : this()
internal FileStorage(string path)
{
this.FileAccess = fileAccess;
this.FileInfo = fileInfo;
this.Path = fileInfo.FullName;
this.m_reference = 0;
this.FileStream = fileInfo.Open(FileMode.OpenOrCreate, fileAccess, FileShare.ReadWrite);
this.m_lockSlim = new ReaderWriterLockSlim();
this.Path = path;
this.m_fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
}
private FileStorage()
{
this.AccessTime = DateTimeOffset.UtcNow;
this.AccessTimeout = TimeSpan.FromSeconds(60);
}
/// <summary>
/// 最后访问时间。
/// </summary>
public DateTimeOffset AccessTime { get; private set; }
/// <summary>
/// 访问超时时间。默认60s
/// </summary>
public TimeSpan AccessTimeout { get; set; }
/// <summary>
/// 访问属性
/// </summary>
public FileAccess FileAccess { get; private set; }
/// <summary>
/// 文件信息
/// </summary>
public FileInfo FileInfo { get; private set; }
/// <summary>
/// 文件流。
/// 一般情况下,请不要直接访问该对象。否则有可能会产生不可预测的错误。
/// </summary>
public FileStream FileStream { get; private set; }
/// <summary>
/// 文件长度
/// </summary>
public long Length => this.FileStream.Length;
/// <summary>
/// 文件路径
/// </summary>
public string Path { get; private set; }
public string Path { get; }
/// <summary>
/// 引用次数。
/// 文件长度
/// </summary>
public int Reference => this.m_reference;
public long Length
{
get
{
this.m_semaphore.Wait();
try
{
this.ThrowIfDisposed();
return this.m_fileStream.Length;
}
finally
{
this.m_semaphore.Release();
}
}
}
public bool CanRead => this.m_fileStream.CanRead;
public bool CanSeek => this.m_fileStream.CanSeek;
public bool CanWrite => this.m_fileStream.CanWrite;
/// <summary>
/// 写入时清空缓存区
/// 设置文件长度
/// </summary>
/// <param name="length">新长度</param>
public void SetLength(long length)
{
this.m_semaphore.Wait();
try
{
this.ThrowIfDisposed();
this.m_fileStream.SetLength(length);
}
finally
{
this.m_semaphore.Release();
}
}
/// <summary>
/// 刷新缓冲区
/// </summary>
public void Flush()
{
this.AccessTime = DateTimeOffset.UtcNow;
this.FileStream.Flush();
}
/// <summary>
/// 从当前文件中读取字节。
/// </summary>
/// <param name="startPos">开始读取的位置。</param>
/// <param name="span">用于接收读取数据的字节跨度。</param>
/// <returns>实际读取的字节数。</returns>
/// <exception cref="ObjectDisposedException">如果当前对象已被处置。</exception>
/// <exception cref="System.IO.IOException">如果文件仅被写入。</exception>
public int Read(long startPos, Span<byte> span)
{
// 更新访问时间,用于跟踪文件的最近访问时间。
this.AccessTime = DateTimeOffset.UtcNow;
// 使用写锁保护共享资源,确保读操作的线程安全性。
using (var writeLock = new WriteLock(this.m_lockSlim))
this.m_semaphore.Wait();
try
{
// 检查对象是否已被处置,如果是,则抛出异常。
if (this.m_disposedValue)
{
ThrowHelper.ThrowObjectDisposedException(this);
}
// 检查文件访问模式,如果是写模式,则抛出异常。
if (this.FileAccess == FileAccess.Write)
{
ThrowHelper.ThrowException(TouchSocketCoreResource.FileOnlyWrittenTo.Format(this.FileInfo.FullName));
}
this.FileStream.Position = startPos;
return this.FileStream.Read(span);
this.ThrowIfDisposed();
this.m_fileStream.Flush();
}
finally
{
this.m_semaphore.Release();
}
}
/// <summary>
/// 减少引用次数,并尝试释放流。
/// </summary>
/// <param name="delayTime">延迟释放时间。当设置为0时立即释放,单位毫秒。</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="Exception"></exception>
public Result TryReleaseFile(int delayTime = 0)
/// <inheritdoc/>
public void Dispose()
{
return FilePool.TryReleaseFile(this.Path, delayTime);
// 通过文件池释放,确保引用计数正确
FilePool.ReleaseFile(this);
}
/// <summary>
/// 写入数据到文件的特定位置。
/// </summary>
/// <param name="startPos">开始写入的位置。</param>
/// <param name="span">要写入的字节跨度。</param>
public void Write(long startPos, ReadOnlySpan<byte> span)
internal void DisposeInternal()
{
// 更新文件的访问时间。
this.AccessTime = DateTimeOffset.UtcNow;
// 使用写锁确保线程安全。
using (var writeLock = new WriteLock(this.m_lockSlim))
{
// 检查对象是否已释放。
if (this.m_disposedValue)
{
// 如果对象已释放抛出ObjectDisposedException。
ThrowHelper.ThrowObjectDisposedException(this);
}
// 检查文件访问权限。
if (this.FileAccess == FileAccess.Read)
{
// 如果文件只读,抛出异常。
ThrowHelper.ThrowException(TouchSocketCoreResource.FileReadOnly.Format(this.FileInfo.FullName));
}
// 设置文件流的位置为指定的开始写入位置。
this.FileStream.Position = startPos;
// 将数据写入文件。
this.FileStream.Write(span);
}
}
internal void Dispose()
{
if (this.m_disposedValue)
if (this.m_disposed)
{
return;
}
using (var writeLock = new WriteLock(this.m_lockSlim))
// 等待获得独占访问,确保没有读写在进行
this.m_semaphore.Wait();
try
{
this.m_disposedValue = true;
this.FileStream.SafeDispose();
if (this.m_disposed)
{
return;
}
this.m_disposed = true;
this.m_fileStream.Dispose();
}
finally
{
// 释放并处置信号量
try
{
this.m_semaphore.Release();
}
catch
{
// 忽略释放异常
}
this.m_semaphore.Dispose();
}
}
private void ThrowIfDisposed()
{
if (this.m_disposed)
{
ThrowHelper.ThrowObjectDisposedException(this);
}
}
/// <summary>
/// 读取数据
/// </summary>
/// <param name="position">读取位置</param>
/// <param name="buffer">缓冲区</param>
/// <param name="offset">缓冲区偏移量</param>
/// <param name="count">读取字节数</param>
/// <returns>实际读取的字节数</returns>
public int Read(long position, byte[] buffer, int offset, int count)
{
this.m_semaphore.Wait();
try
{
this.ThrowIfDisposed();
this.m_fileStream.Position = position;
return this.m_fileStream.Read(buffer, offset, count);
}
finally
{
this.m_semaphore.Release();
}
}
/// <summary>
/// 写入数据
/// </summary>
/// <param name="position">写入位置</param>
/// <param name="buffer">数据</param>
/// <param name="offset">缓冲区偏移量</param>
/// <param name="count">写入字节数</param>
public void Write(long position, byte[] buffer, int offset, int count)
{
this.m_semaphore.Wait();
try
{
this.ThrowIfDisposed();
this.m_fileStream.Position = position;
this.m_fileStream.Write(buffer, offset, count);
}
finally
{
this.m_semaphore.Release();
}
}
/// <summary>
/// 异步读取数据
/// </summary>
/// <param name="position">读取位置</param>
/// <param name="memory">缓冲区</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>实际读取的字节数</returns>
public async Task<int> ReadAsync(long position, Memory<byte> memory, CancellationToken cancellationToken = default)
{
await this.m_semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
this.ThrowIfDisposed();
this.m_fileStream.Position = position;
return await this.m_fileStream.ReadAsync(memory, cancellationToken).ConfigureAwait(false);
}
finally
{
this.m_semaphore.Release();
}
}
/// <summary>
/// 异步写入数据
/// </summary>
/// <param name="position">写入位置</param>
/// <param name="memory">数据</param>
/// <param name="cancellationToken">取消令牌</param>
public async Task WriteAsync(long position, ReadOnlyMemory<byte> memory, CancellationToken cancellationToken = default)
{
await this.m_semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
this.ThrowIfDisposed();
this.m_fileStream.Position = position;
await this.m_fileStream.WriteAsync(memory, cancellationToken).ConfigureAwait(false);
}
finally
{
this.m_semaphore.Release();
}
}
/// <summary>
/// 异步刷新缓冲区
/// </summary>
/// <param name="cancellationToken">取消令牌</param>
public async Task FlushAsync(CancellationToken cancellationToken = default)
{
await this.m_semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
this.ThrowIfDisposed();
await this.m_fileStream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
finally
{
this.m_semaphore.Release();
}
}
/// <summary>
/// 读取数据
/// </summary>
/// <param name="position">读取位置</param>
/// <param name="buffer">缓冲区</param>
/// <returns>实际读取的字节数</returns>
public int Read(long position, Span<byte> buffer)
{
this.m_semaphore.Wait();
try
{
this.ThrowIfDisposed();
this.m_fileStream.Position = position;
return this.m_fileStream.Read(buffer);
}
finally
{
this.m_semaphore.Release();
}
}
/// <summary>
/// 写入数据
/// </summary>
/// <param name="position">写入位置</param>
/// <param name="buffer">数据</param>
public void Write(long position, ReadOnlySpan<byte> buffer)
{
this.m_semaphore.Wait();
try
{
this.ThrowIfDisposed();
this.m_fileStream.Position = position;
this.m_fileStream.Write(buffer);
}
finally
{
this.m_semaphore.Release();
}
}
}

View File

@@ -1,77 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在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://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
namespace TouchSocket.Core;
/// <summary>
/// 文件读取器
/// </summary>
public partial class FileStorageReader : SafetyDisposableObject
{
private long m_position;
/// <summary>
/// 初始化FileStorageReader实例。
/// </summary>
/// <param name="fileStorage">文件存储对象,用于处理文件读取操作。</param>
/// <remarks>
/// 此构造函数接收一个FileStorage对象作为参数用于后续的文件读取操作。
/// 如果传入的FileStorage对象为<see langword="null"/>则抛出ArgumentNullException异常
/// 这确保了文件读取操作不会在不合法的参数状态下执行,提高了代码的健壮性。
/// </remarks>
public FileStorageReader(FileStorage fileStorage)
{
ThrowHelper.ThrowIfNull(fileStorage, nameof(fileStorage));
this.FileStorage = fileStorage;
}
/// <summary>
/// 析构函数
/// </summary>
~FileStorageReader()
{
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
this.Dispose(disposing: false);
}
/// <summary>
/// 文件存储器
/// </summary>
public FileStorage FileStorage { get; private set; }
/// <summary>
/// 游标位置
/// </summary>
public long Position { get => this.m_position; set => this.m_position = value; }
/// <summary>
/// 从文件存储中读取字节到指定的字节跨度。
/// </summary>
/// <param name="span">要读取数据的字节跨度。</param>
/// <returns>实际读取到的字节数。</returns>
public int Read(Span<byte> span)
{
// 调用文件存储从当前位置读取数据到字节跨度中
var r = this.FileStorage.Read(this.Position, span);
// 使用Interlocked类原子性地更新当前位置以确保多线程环境下的安全性
Interlocked.Add(ref this.m_position, r);
// 返回实际读取到的字节数
return r;
}
/// <inheritdoc/>
protected override void SafetyDispose(bool disposing)
{
FilePool.TryReleaseFile(this.FileStorage.Path);
this.FileStorage = null;
}
}

View File

@@ -10,111 +10,237 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
namespace TouchSocket.Core;
/// <summary>
/// FileStorageStream。
/// 文件存储流
/// </summary>
public partial class FileStorageStream : Stream
internal sealed partial class FileStorageStream : Stream
{
private long m_position;
private int m_dis = 1;
private FileStorage m_storage;
private bool m_disposed;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="fileStorage"></param>
public FileStorageStream(FileStorage fileStorage)
internal FileStorageStream(FileStorage storage)
{
ThrowHelper.ThrowIfNull(fileStorage, nameof(fileStorage));
this.FileStorage = fileStorage;
}
/// <summary>
/// 析构函数
/// </summary>
~FileStorageStream()
{
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
this.Dispose(disposing: false);
this.m_storage = storage;
}
/// <inheritdoc/>
public override bool CanRead => this.FileStorage.FileStream.CanRead;
public override bool CanRead => this.m_storage.CanRead;
/// <inheritdoc/>
public override bool CanSeek => this.FileStorage.FileStream.CanSeek;
public override bool CanSeek => this.m_storage.CanSeek;
/// <inheritdoc/>
public override bool CanWrite => this.FileStorage.FileStream.CanWrite;
/// <summary>
/// 文件存储器
/// </summary>
public FileStorage FileStorage { get; private set; }
public override bool CanWrite => this.m_storage.CanWrite;
/// <inheritdoc/>
public override long Length => this.FileStorage.FileStream.Length;
public override long Length
{
get
{
this.ThrowIfDisposed();
return this.m_storage.Length;
}
}
/// <inheritdoc/>
public override long Position { get => this.m_position; set => this.m_position = value; }
public override long Position
{
get => this.m_position;
set => this.m_position = value;
}
/// <inheritdoc/>
public override void Flush()
{
this.FileStorage.Flush();
this.ThrowIfDisposed();
this.m_storage.Flush();
}
/// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count)
{
var r = this.FileStorage.Read(this.m_position, new System.Span<byte>(buffer, offset, count));
this.m_position += r;
return r;
this.ThrowIfDisposed();
#if NET6_0_OR_GREATER
var span = buffer.AsSpan(offset, count);
var readCount = this.m_storage.Read(this.m_position, span);
this.m_position += readCount;
return readCount;
#else
return this.ReadCore(buffer, offset, count);
#endif
}
/// <inheritdoc/>
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
this.ThrowIfDisposed();
this.m_position = origin switch
{
case SeekOrigin.Begin:
this.m_position = offset;
break;
case SeekOrigin.Current:
this.m_position += offset;
break;
case SeekOrigin.End:
this.m_position = this.Length + offset;
break;
}
SeekOrigin.Begin => offset,
SeekOrigin.Current => this.m_position + offset,
SeekOrigin.End => this.m_storage.Length + offset,
_ => throw new ArgumentException("Invalid seek origin", nameof(origin))
};
return this.m_position;
}
/// <inheritdoc/>
public override void SetLength(long value)
{
this.FileStorage.FileStream.SetLength(value);
this.ThrowIfDisposed();
this.m_storage.SetLength(value);
}
/// <inheritdoc/>
public override void Write(byte[] buffer, int offset, int count)
{
this.FileStorage.Write(this.m_position, new System.ReadOnlySpan<byte>(buffer, offset, count));
this.ThrowIfDisposed();
#if NET6_0_OR_GREATER
var span = buffer.AsSpan(offset, count);
this.m_storage.Write(this.m_position, span);
this.m_position += count;
#else
this.WriteCore(buffer, offset, count);
#endif
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
if (Interlocked.Decrement(ref this.m_dis) == 0)
if (this.m_disposed)
{
FilePool.TryReleaseFile(this.FileStorage.Path);
this.FileStorage = null;
return;
}
this.m_disposed = true;
if (disposing && this.m_storage != null)
{
FilePool.ReleaseFile(this.m_storage);
this.m_storage = null;
}
base.Dispose(disposing);
}
}
private void ThrowIfDisposed()
{
if (this.m_disposed)
{
ThrowHelper.ThrowObjectDisposedException(this);
}
}
}
#if NET6_0_OR_GREATER
internal sealed partial class FileStorageStream
{
/// <inheritdoc/>
public override int Read(Span<byte> buffer)
{
this.ThrowIfDisposed();
var count = this.m_storage.Read(this.m_position, buffer);
this.m_position += count;
return count;
}
/// <inheritdoc/>
public override void Write(ReadOnlySpan<byte> buffer)
{
this.ThrowIfDisposed();
this.m_storage.Write(this.m_position, buffer);
this.m_position += buffer.Length;
}
/// <inheritdoc/>
public override Task FlushAsync(CancellationToken cancellationToken)
{
this.ThrowIfDisposed();
return this.m_storage.FlushAsync(cancellationToken);
}
/// <inheritdoc/>
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
this.ThrowIfDisposed();
var memory = buffer.AsMemory(offset, count);
var readCount = await this.m_storage.ReadAsync(this.m_position, memory, cancellationToken).ConfigureAwait(false);
this.m_position += readCount;
return readCount;
}
/// <inheritdoc/>
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
this.ThrowIfDisposed();
var count = await this.m_storage.ReadAsync(this.m_position, buffer, cancellationToken).ConfigureAwait(false);
this.m_position += count;
return count;
}
/// <inheritdoc/>
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
this.ThrowIfDisposed();
var memory = buffer.AsMemory(offset, count);
await this.m_storage.WriteAsync(this.m_position, memory, cancellationToken).ConfigureAwait(false);
this.m_position += count;
}
/// <inheritdoc/>
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
this.ThrowIfDisposed();
await this.m_storage.WriteAsync(this.m_position, buffer, cancellationToken).ConfigureAwait(false);
this.m_position += buffer.Length;
}
}
#endif
#if NETSTANDARD2_0 || NETSTANDARD2_1 || NET462
internal sealed partial class FileStorageStream
{
private int ReadCore(byte[] buffer, int offset, int count)
{
var readCount = this.m_storage.Read(this.m_position, buffer, offset, count);
this.m_position += readCount;
return readCount;
}
private void WriteCore(byte[] buffer, int offset, int count)
{
this.m_storage.Write(this.m_position, buffer, offset, count);
this.m_position += count;
}
/// <inheritdoc/>
public override Task FlushAsync(CancellationToken cancellationToken)
{
this.ThrowIfDisposed();
return this.m_storage.FlushAsync(cancellationToken);
}
/// <inheritdoc/>
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
this.ThrowIfDisposed();
var readCount = await this.m_storage.ReadAsync(this.m_position, new Memory<byte>(buffer, offset, count), cancellationToken).ConfigureAwait(false);
this.m_position += readCount;
return readCount;
}
/// <inheritdoc/>
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
this.ThrowIfDisposed();
await this.m_storage.WriteAsync(this.m_position, new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).ConfigureAwait(false);
this.m_position += count;
}
}
#endif

View File

@@ -1,81 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在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://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
namespace TouchSocket.Core;
/// <summary>
/// 文件写入器。
/// </summary>
public partial class FileStorageWriter : SafetyDisposableObject
{
private long m_position;
/// <summary>
/// 初始化FileStorageWriter的实例。
/// </summary>
/// <param name="fileStorage">文件存储服务的实例,用于后续的文件写入操作。</param>
public FileStorageWriter(FileStorage fileStorage)
{
ThrowHelper.ThrowIfNull(fileStorage, nameof(fileStorage));
this.FileStorage = fileStorage;
}
/// <summary>
/// 析构函数
/// </summary>
~FileStorageWriter()
{
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
this.Dispose(disposing: false);
}
/// <summary>
/// 文件存储器
/// </summary>
public FileStorage FileStorage { get; private set; }
/// <summary>
/// 游标位置
/// </summary>
public long Position { get => this.m_position; set => this.m_position = value; }
/// <summary>
/// 将文件指针移动到文件末尾。
/// </summary>
/// <returns>返回文件末尾的位置。</returns>
public long SeekToEnd()
{
// 设置文件指针到文件末尾,并返回该位置
return this.Position = this.FileStorage.Length;
}
/// <summary>
/// 将一组只读字节写入文件存储。
/// </summary>
/// <param name="span">要写入的只读字节范围。</param>
public void Write(ReadOnlySpan<byte> span)
{
// 调用FileStorage的Write方法将当前Position位置的span长度字节写入。
this.FileStorage.Write(this.Position, span);
// 使用Interlocked类的Add方法线程安全地更新当前Position。
Interlocked.Add(ref this.m_position, span.Length);
}
/// <inheritdoc/>
protected override void SafetyDispose(bool disposing)
{
FilePool.TryReleaseFile(this.FileStorage.Path);
this.FileStorage = null;
}
}

View File

@@ -21,7 +21,7 @@ namespace TouchSocket.Core;
public sealed class FileLogger : LoggerBase, IDisposable
{
private const int MaxRetryCount = 10;
private readonly ConcurrentDictionary<string, FileStorageWriter> m_writers = new ConcurrentDictionary<string, FileStorageWriter>();
private readonly ConcurrentDictionary<string, Stream> m_writers = new();
private Func<LogLevel, string> m_createLogFolder;
private bool m_disposedValue;
private int m_retryCount;
@@ -117,7 +117,7 @@ public sealed class FileLogger : LoggerBase, IDisposable
}
}
private FileStorageWriter GetFileStorageWriter(string dirPath)
private Stream GetFileStorageWriter(string dirPath)
{
if (this.m_writers.TryGetValue(dirPath, out var writer))
{
@@ -136,9 +136,8 @@ public sealed class FileLogger : LoggerBase, IDisposable
var filePath = Path.Combine(dirPath, $"{count.ToString(this.FileNameFormat)}" + ".log");
if (!(File.Exists(filePath) && new FileInfo(filePath).Length > this.MaxSize))
{
writer = FilePool.GetWriter(filePath);
writer.SeekToEnd();
writer.FileStorage.AccessTimeout = TimeSpan.MaxValue;
writer = FilePool.GetStream(filePath);
writer.Seek(writer.Length, SeekOrigin.Begin);
return this.m_writers.TryAdd(dirPath, writer) ? writer : this.GetFileStorageWriter(dirPath);
}
@@ -158,8 +157,8 @@ public sealed class FileLogger : LoggerBase, IDisposable
try
{
writer1.Write((Encoding.UTF8.GetBytes(logString)));
writer1.FileStorage.Flush();
if (writer1.FileStorage.Length > this.MaxSize)
writer1.Flush();
if (writer1.Length > this.MaxSize)
{
if (this.m_writers.TryRemove(dirPath, out var fileStorageWriter))
{

View File

@@ -591,91 +591,51 @@ internal sealed class DmtpFileTransferActor : DisposableObject, IDmtpFileTransfe
/// <inheritdoc/>
public async Task<FinishedResult> FinishedFileResourceInfoAsync(string targetId, FileResourceInfo fileResourceInfo, ResultCode code, Metadata metadata, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(targetId))
{
return await this.PrivateFinishedFileResourceInfoAsync(targetId, fileResourceInfo, code, metadata, cancellationToken);
}
if (this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor)
{
return await actor.FinishedFileResourceInfoAsync(fileResourceInfo, code, metadata, cancellationToken);
}
else
{
return await this.PrivateFinishedFileResourceInfoAsync(targetId, fileResourceInfo, code, metadata, cancellationToken);
}
return string.IsNullOrEmpty(targetId)
? await this.PrivateFinishedFileResourceInfoAsync(targetId, fileResourceInfo, code, metadata, cancellationToken)
: this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor
? await actor.FinishedFileResourceInfoAsync(fileResourceInfo, code, metadata, cancellationToken)
: await this.PrivateFinishedFileResourceInfoAsync(targetId, fileResourceInfo, code, metadata, cancellationToken);
}
/// <inheritdoc/>
public async Task<FileResourceInfoResult> PullFileResourceInfoAsync(string targetId, string path, Metadata metadata, int fileSectionSize, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(targetId))
{
return await this.PrivatePullFileResourceInfoAsync(targetId, path, metadata, fileSectionSize, cancellationToken);
}
if (this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor)
{
return await actor.PullFileResourceInfoAsync(path, metadata, fileSectionSize, cancellationToken);
}
else
{
return await this.PrivatePullFileResourceInfoAsync(targetId, path, metadata, fileSectionSize, cancellationToken);
}
return string.IsNullOrEmpty(targetId)
? await this.PrivatePullFileResourceInfoAsync(targetId, path, metadata, fileSectionSize, cancellationToken)
: this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor
? await actor.PullFileResourceInfoAsync(path, metadata, fileSectionSize, cancellationToken)
: await this.PrivatePullFileResourceInfoAsync(targetId, path, metadata, fileSectionSize, cancellationToken);
}
/// <inheritdoc/>
public async Task<FileSectionResult> PullFileSectionAsync(string targetId, FileSection fileSection, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(targetId))
{
return await this.PrivatePullFileSectionAsync(targetId, fileSection, cancellationToken);
}
if (this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor)
{
return await actor.PullFileSectionAsync(fileSection, cancellationToken);
}
else
{
return await this.PrivatePullFileSectionAsync(targetId, fileSection, cancellationToken);
}
return string.IsNullOrEmpty(targetId)
? await this.PrivatePullFileSectionAsync(targetId, fileSection, cancellationToken)
: this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor
? await actor.PullFileSectionAsync(fileSection, cancellationToken)
: await this.PrivatePullFileSectionAsync(targetId, fileSection, cancellationToken);
}
/// <inheritdoc/>
public async Task<Result> PushFileResourceInfoAsync(string targetId, string savePath, FileResourceLocator fileResourceLocator, Metadata metadata, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(targetId))
{
return await this.PrivatePushFileResourceInfoAsync(targetId, savePath, fileResourceLocator, metadata, cancellationToken);
}
if (this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor)
{
return await actor.PushFileResourceInfoAsync(savePath, fileResourceLocator, metadata, cancellationToken);
}
else
{
return await this.PrivatePushFileResourceInfoAsync(targetId, savePath, fileResourceLocator, metadata, cancellationToken);
}
return string.IsNullOrEmpty(targetId)
? await this.PrivatePushFileResourceInfoAsync(targetId, savePath, fileResourceLocator, metadata, cancellationToken)
: this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor
? await actor.PushFileResourceInfoAsync(savePath, fileResourceLocator, metadata, cancellationToken)
: await this.PrivatePushFileResourceInfoAsync(targetId, savePath, fileResourceLocator, metadata, cancellationToken);
}
/// <inheritdoc/>
public async Task<Result> PushFileSectionAsync(string targetId, FileResourceLocator fileResourceLocator, FileSection fileSection, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(targetId))
{
return await this.PrivatePushFileSectionAsync(targetId, fileResourceLocator, fileSection, cancellationToken);
}
if (this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor)
{
return await actor.PushFileSectionAsync(fileResourceLocator, fileSection, cancellationToken);
}
else
{
return await this.PrivatePushFileSectionAsync(targetId, fileResourceLocator, fileSection, cancellationToken);
}
return string.IsNullOrEmpty(targetId)
? await this.PrivatePushFileSectionAsync(targetId, fileResourceLocator, fileSection, cancellationToken)
: this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor
? await actor.PushFileSectionAsync(fileResourceLocator, fileSection, cancellationToken)
: await this.PrivatePushFileSectionAsync(targetId, fileResourceLocator, fileSection, cancellationToken);
}
#endregion Id传输
@@ -1263,7 +1223,7 @@ internal sealed class DmtpFileTransferActor : DisposableObject, IDmtpFileTransfe
if (this.FileController.TryGetFileResourceLocator(waitFileSection.FileSection.ResourceHandle,
out var locator))
{
var r = locator.ReadBytes(waitFileSection.FileSection.Offset, bufferByteBlock.TotalMemory.Span.Slice(0, length));
var r = await locator.ReadAsync(waitFileSection.FileSection.Offset, bufferByteBlock.TotalMemory.Slice(0, length));
if (r == length)
{
waitFileSection.Status = TouchSocketDmtpStatus.Success.ToValue();
@@ -1435,14 +1395,9 @@ internal sealed class DmtpFileTransferActor : DisposableObject, IDmtpFileTransfe
/// <inheritdoc/>
public async Task<PullSmallFileResult> PullSmallFileAsync(string targetId, string path, Metadata metadata = default, CancellationToken cancellationToken = default)
{
if (this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor)
{
return await actor.PullSmallFileAsync(path, metadata, cancellationToken);
}
else
{
return await this.PrivatePullSmallFileAsync(targetId, path, metadata, cancellationToken);
}
return this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor
? await actor.PullSmallFileAsync(path, metadata, cancellationToken)
: await this.PrivatePullSmallFileAsync(targetId, path, metadata, cancellationToken);
}
/// <inheritdoc/>
@@ -1454,14 +1409,9 @@ internal sealed class DmtpFileTransferActor : DisposableObject, IDmtpFileTransfe
/// <inheritdoc/>
public async Task<Result> PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = default, CancellationToken cancellationToken = default)
{
if (this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor)
{
return await actor.PushSmallFileAsync(savePath, fileInfo, metadata, cancellationToken);
}
else
{
return await this.PrivatePushSmallFileAsync(targetId, savePath, fileInfo, metadata, cancellationToken);
}
return this.DmtpActor.AllowRoute && (await this.TryFindDmtpFileTransferActor(targetId)) is DmtpFileTransferActor actor
? await actor.PushSmallFileAsync(savePath, fileInfo, metadata, cancellationToken)
: await this.PrivatePushSmallFileAsync(targetId, savePath, fileInfo, metadata, cancellationToken);
}
/// <inheritdoc/>

View File

@@ -30,7 +30,7 @@ public class FileResourceLocator : DisposableObject
{
this.FileResourceInfo = fileResourceInfo;
this.FileAccess = FileAccess.Read;
this.FileStorage = FilePool.GetFileStorageForRead(fileResourceInfo.FileInfo.FullName);
this.FileStorage = FilePool.GetStorage(fileResourceInfo.FileInfo.FullName);
this.LocatorPath = fileResourceInfo.FileInfo.FullName;
this.LastActiveTime = DateTimeOffset.UtcNow;
}
@@ -55,7 +55,7 @@ public class FileResourceLocator : DisposableObject
this.LocatorPath = locatorPath;
this.FileResourceInfo = fileResourceInfo;
this.FileAccess = FileAccess.Write;
this.FileStorage = FilePool.GetFileStorageForWrite(this.LocatorPath + ExtensionName);
this.FileStorage = FilePool.GetStorage(this.LocatorPath + ExtensionName);
this.LastActiveTime = DateTimeOffset.UtcNow;
}
@@ -115,9 +115,7 @@ public class FileResourceLocator : DisposableObject
// 根据文件访问模式决定返回值
// 如果是读取模式,则返回空数组
// 否则,返回所有未完成状态的文件片段集合
return this.FileAccess == FileAccess.Read
? (new FileSection[0])
: this.FileResourceInfo.FileSections.Where(a => a.Status != FileSectionStatus.Finished).ToArray();
return this.FileAccess == FileAccess.Read ? [] : this.FileResourceInfo.FileSections.Where(a => a.Status != FileSectionStatus.Finished).ToArray();
}
/// <summary>
@@ -126,12 +124,10 @@ public class FileResourceLocator : DisposableObject
/// <param name="pos">要开始读取的文件位置。</param>
/// <param name="span">用于存储读取的字节的跨度。</param>
/// <returns>读取的字节数。</returns>
public int ReadBytes(long pos, Span<byte> span)
public async Task<int> ReadAsync(long pos, Memory<byte> span)
{
// 更新最后一次活动时间,用于跟踪访问时间
this.LastActiveTime = DateTimeOffset.UtcNow;
// 调用底层文件存储系统的读取方法,读取字节并返回读取的字节数
return this.FileStorage.Read(pos, span);
return await this.FileStorage.ReadAsync(pos, span);
}
/// <summary>
@@ -234,14 +230,7 @@ public class FileResourceLocator : DisposableObject
return new Result(ResultCode.Failure, "文件长度不一致。");
}
// 尝试释放文件最多尝试10次
for (var i = 0; i < 10; i++)
{
if (this.FileStorage.TryReleaseFile().IsSuccess)
{
break;
}
}
this.FileStorage.Dispose();
// 确保文件移动并重命名最多尝试10次
for (var i = 0; i < 10; i++)
@@ -350,7 +339,7 @@ public class FileResourceLocator : DisposableObject
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
this.FileStorage.TryReleaseFile();
this.FileStorage.Dispose();
base.Dispose(disposing);
}
}

View File

@@ -9,7 +9,6 @@
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
namespace TouchSocket.Dmtp.FileTransfer;
/// <summary>
@@ -55,8 +54,9 @@ public class PullSmallFileResult : ResultBase
/// </summary>
/// <param name="path">要保存文件的路径。</param>
/// <param name="overwrite">是否覆盖同名文件,默认为<see langword="true"/>。</param>
/// <param name="cancellationToken">可取消令箭</param>
/// <returns>返回保存结果。</returns>
public Result Save(string path, bool overwrite = true)
public async Task<Result> SaveAsync(string path, bool overwrite = true, CancellationToken cancellationToken = default)
{
try
{
@@ -64,11 +64,13 @@ public class PullSmallFileResult : ResultBase
{
FileUtility.Delete(path);
}
using (var byteBlock = FilePool.GetWriter(path))
using (var stream = FilePool.GetStream(path))
{
byteBlock.Write(this.Value);
return Result.Success;
await stream.WriteAsync(this.Value, cancellationToken);
await stream.FlushAsync(cancellationToken);
}
return Result.Success;
}
catch (Exception ex)
{

View File

@@ -95,9 +95,9 @@ public class FileResourceController : DisposableObject, IFileResourceController
public virtual int ReadAllBytes(FileInfo fileInfo, byte[] buffer)
{
this.ThrowIfDisposed();
using (var byteBlock = FilePool.GetReader(fileInfo))
using (var stream = FilePool.GetStream(fileInfo.FullName))
{
return byteBlock.Read(buffer);
return stream.Read(buffer);
}
}
@@ -125,9 +125,9 @@ public class FileResourceController : DisposableObject, IFileResourceController
public virtual void WriteAllBytes(string path, byte[] buffer, int offset, int length)
{
this.ThrowIfDisposed();
using (var byteBlock = FilePool.GetWriter(path))
using (var stream = FilePool.GetStream(path))
{
byteBlock.Write(new ReadOnlySpan<byte>(buffer, offset, length));
stream.Write(new ReadOnlySpan<byte>(buffer, offset, length));
}
}

View File

@@ -298,7 +298,6 @@ public class DmtpRpcActor : DisposableObject, IDmtpRpcActor
}
else
{
//首先移除调用上下文。
this.m_callContextDic.TryRemove(rpcRequestPackage.Sign, out _);
}

View File

@@ -65,22 +65,6 @@ public abstract partial class HttpSessionClient : TcpSessionClientBase, IHttpSes
return base.OnTcpConnecting(e);
}
/// <inheritdoc/>
protected sealed override async ValueTask<bool> OnTcpReceiving(IBytesReader reader)
{
var webSocket = this.m_webSocket;
if (webSocket is null)
{
await this.m_httpAdapter.ReceivedInputAsync(reader).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
}
else
{
await this.m_webSocketAdapter.ReceivedInputAsync(reader).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
}
return true;
}
private async Task OnReceivingHttpRequest(ServerHttpRequest request)
{
if (this.m_httpContext == null)