gpt4 book ai didi

c# - 如何在 C# winform 应用程序中写入非缓存文件

转载 作者:可可西里 更新时间:2023-11-01 08:10:12 26 4
gpt4 key购买 nike

我试图确定最坏情况下的磁盘速度,因此我编写了以下函数。

static public decimal MBytesPerSec(string volume)
{
string filename = volume + "\\writetest.tmp";

if (System.IO.File.Exists(filename))
System.IO.File.Delete(filename);

System.IO.StreamWriter file = new System.IO.StreamWriter(filename);

char[] data = new char[64000];
Stopwatch watch = new Stopwatch();
watch.Start();

int i = 0;

for (; i < 1000; i++)
{
file.Write(data);
if (watch.ElapsedMilliseconds > 2000)
{
break;
}
}

watch.Stop();
file.Close();

System.IO.File.Delete(volume + "\\test.txt");
decimal mbytessec = (i * 64 / watch.ElapsedMilliseconds);
return mbytessec;
}

函数工作正常,但写入被缓存,所以速度不是最坏的情况。

在 WIN32 C++ 中,我会简单地使用 FILE_FLAG_NO_BUFFERINGFILE_FLAG_WRITE_THROUGH 选项创建文件,然后确保遵循非缓存写入规则(写入文件在扇区大小偏移处,最少写入 4k)

我找到一个 article讨论 .NET 技术。

所以我写了一个新函数(忽略数学错误)。

static public decimal MBytesPerSecNonCached(string volume)
{
const FileOptions FILE_FLAG_NO_BUFFERING = (FileOptions)0x20000000;

string filename = volume + "\\writetest.tmp";

using (FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 1024, FileOptions.WriteThrough | FILE_FLAG_NO_BUFFERING))
{
byte[] data = new byte[65535];
int i = 0;

Stopwatch watch = new Stopwatch();
watch.Start();

for (; i < 1000; i++)
{
fs.Write(data, 0, 65535);
if (watch.ElapsedMilliseconds > 2000)
{
break;
}
}

watch.Stop();
fs.Close();

System.IO.File.Delete(filename);

decimal mbytessec = (i * 64 / watch.ElapsedMilliseconds);

return mbytessec;
}
}

此函数适用于 4k、16K 和 32K 写入大小,但一旦我尝试 64K 写入大小,就会出现异常:

IO operation will not work. Most likely the file will become too long or the handle was not opened to support synchronous IO operations.

那么,我该如何解决这个问题,以便我可以测试大于 32KB 的写入大小(64KB 到 4096KB)?

最佳答案

尝试一些非托管代码:

[DllImport("kernel32", SetLastError = true)]
static extern unsafe SafeFileHandle CreateFile(
string FileName, // file name
uint DesiredAccess, // access mode
uint ShareMode, // share mode
IntPtr SecurityAttributes, // Security Attr
uint CreationDisposition, // how to create
uint FlagsAndAttributes, // file attributes
IntPtr hTemplate // template file
);
const uint FILE_FLAG_NO_BUFFERING = 0x20000000;

SafeFileHandle handle = CreateFile("filename",
(uint)FileAccess.Write,
(uint)FileShare.None,
IntPtr.Zero,
(uint)FileMode.Open,
FILE_FLAG_NO_BUFFERING,
IntPtr.Zero);

var unBufferedStream = new FileStream(handle,FileAccess.Read,blockSize,false);

现在你应该可以访问一个无缓冲的流,你可以不受限制地读写它

郑重声明....您也可以像这样禁用缓存:

[DllImport("KERNEL32", SetLastError = true)]
public extern static int DeviceIoControl(IntPtr hDevice, uint IoControlCode,
IntPtr lpInBuffer, uint InBufferSize,
IntPtr lpOutBuffer, uint nOutBufferSize,
ref uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport("KERNEL32", SetLastError = true)]
public extern static int CloseHandle(
IntPtr hObject);

[StructLayout(LayoutKind.Sequential)]
public struct DISK_CACHE_INFORMATION
{
public byte ParametersSavable;
public byte ReadCacheEnabled;
public byte WriteCacheEnabled;
public int ReadRetentionPriority;//DISK_CACHE_RETENTION_PRIORITY = enum = int
public int WriteRetentionPriority;//DISK_CACHE_RETENTION_PRIORITY = enum = int
public Int16 DisablePrefetchTransferLength;//WORD
public byte PrefetchScalar;
}

public void SetDiskCache(byte val)
{
IntPtr h = CreateFile("\\\\.\\PHYSICALDRIVE0", (uint)FileAccess.Read | (uint)FileAccess.Write, (uint)FileShare.Write, IntPtr.Zero, (uint)FileMode.Open, 0, IntPtr.Zero);
DISK_CACHE_INFORMATION sInfo = new DISK_CACHE_INFORMATION();
IntPtr ptrout = Marshal.AllocHGlobal(Marshal.SizeOf(sInfo));
Marshal.StructureToPtr(sInfo, ptrout, true);
uint dwWritten = 0;
int ret = DeviceIoControl(h,IOCTL_DISK_GET_CACHE_INFORMATION,IntPtr.Zero,0,ptrout,(uint)Marshal.SizeOf(sInfo),ref dwWritten,IntPtr.Zero);
sInfo = (DISK_CACHE_INFORMATION)Marshal.PtrToStructure(ptrout,typeof(DISK_CACHE_INFORMATION));
sInfo.ReadCacheEnabled = val;
// acuma trimite structura modificata
IntPtr ptrin = Marshal.AllocHGlobal(Marshal.SizeOf(sInfo));
Marshal.StructureToPtr(sInfo, ptrin, true);
ret = DeviceIoControl(h, IOCTL_DISK_SET_CACHE_INFORMATION, ptrin, (uint)Marshal.SizeOf(sInfo), IntPtr.Zero, 0, ref dwWritten, IntPtr.Zero);
CloseHandle(h);
}

关于c# - 如何在 C# winform 应用程序中写入非缓存文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5916673/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com