评估驱动器是不是正在使用中
Posted
技术标签:
【中文标题】评估驱动器是不是正在使用中【英文标题】:Evaluate if drive is in use评估驱动器是否正在使用中 【发布时间】:2018-02-18 11:51:18 【问题描述】:我想使用 C# 评估驱动器是否正在使用(如果我没记错的话,这意味着驱动器正在发生一些读/写事情)。我不介意使用 bash 脚本或类似脚本的解决方案,因为我可以在 C# 应用程序中使用它们。我已经找到了一个关于 bash 脚本的问题 here,但无法用给出的答案解决我的问题。
我已经考虑过使用DriveInfo
类,但是它似乎对我没有任何用处。我想知道我是否可以使用来自DriveInfo
的IsReady
属性,因为我猜它在读/写时不会准备好,但这种尝试对我来说似乎相当拙劣。
不过我还是试过了:
private static bool IsDriveInUse ()
var drive = DriveInfo.GetDrives ().FirstOrDefault(info => info.Name.StartsWith(DRIVE_LETTER.ToString()));
return drive != null && !drive.IsReady;
但它不起作用(当我从驱动器播放音乐时它返回 false)。
对我来说最佳解决方案是一个函数,它告诉我驱动器是否在特定时间段内使用(让我们坚持使用名称IsDriveInUse
)。这意味着如果时间是例如 60 秒,如果在从驱动器读取函数调用内容前 5 秒,IsDriveInUse
应该返回 true
,如果在过去的 60 秒内没有读/写操作,则应该返回 false
.
编辑为了具体说明使用中的确切含义,我将尝试解释我正在尝试做的事情。我正在编写一个工具,当它空闲或按下键盘快捷键时,它会自动降低硬盘驱动器的转速。我设法以编程方式将其降速(即使 Windows 集成工具或我发现的其他工具都能够做到这一点,但这是另一个问题)。但是,它现在每分钟都会使硬盘驱动器减速,无论它当前是否正在使用。这意味着,如果我从硬盘播放音乐,它仍然会减速,只是在它之后直接加速,这不会减少噪音的产生。
我希望这可以澄清问题。
编辑我现在尝试使用FSCTL_LOCK_VOLUME
控制代码(我找不到IOCTL_DISK_PERFORMANCE
的值),但在我玩游戏时它仍然为IsDriveInUse()
返回false
音乐。此外,当我向下旋转它时,它会导致 Windows 直接再次旋转驱动器(可能是因为发布使 Windows 认为某些东西正在使用驱动器)。这是我尝试过的:
public class DriveManager
public const int FSCTL_LOCK_VOLUME = 0x00090018;
public const int FSCTL_UNLOCK_VOLUME = 0x0009001c;
[DllImport ("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CreateFile (
string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes,
uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[return: MarshalAs (UnmanagedType.Bool)]
[DllImport ("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool DeviceIoControl (
[In] SafeFileHandle hDevice,
[In] int dwIoControlCode, [In] IntPtr lpInBuffer,
[In] int nInBufferSize, [Out] IntPtr lpOutBuffer,
[In] int nOutBufferSize, out int lpBytesReturned,
[In] IntPtr lpOverlapped);
public static SafeFileHandle CreateFileR (string device)
string str = device.EndsWith (@"\") ? device.Substring (0, device.Length - 1) : device;
return new SafeFileHandle (
CreateFile (@"\\.\" + str, WinntConst.GENERIC_READ, WinntConst.FILE_SHARE_READ, IntPtr.Zero,
WinntConst.OPEN_EXISTING, WinntConst.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);
internal class WinntConst
// Fields
internal static uint FILE_ATTRIBUTE_NORMAL = 0x80;
internal static uint FILE_SHARE_READ = 1;
internal static uint GENERIC_READ = 0x80000000;
internal static uint OPEN_EXISTING = 3;
public static bool IsDriveInUse (string deviceName)
var handle = CreateFileR (deviceName);
var buffer = Marshal.AllocHGlobal (sizeof (int));
try
return
DeviceIoControl (handle,
FSCTL_LOCK_VOLUME,
IntPtr.Zero,
0,
buffer,
sizeof(int),
out var bytesReturned,
IntPtr.Zero
);
finally
var sessionId = Marshal.ReadInt32 (buffer);
Marshal.FreeHGlobal (buffer);
handle.Close ();
以及实现:
private static bool IsDriveInUse () => DriveManager.IsDriveInUse ($@"DRIVE_LETTER:\");
也许它有助于查看我正在旋转光盘的部分(我为此使用了Smartmontools):
internal static class Program
private const string PROGRAM_PATH = @"External\smartctl.exe";
private const string ARGUMENTS_SHUTDOWN = @"-s standby,now 0:";
private const char DRIVE_LETTER = 'd';
public static void Main (string [] args)
InitializeHotKey ();
Console.WriteLine ("Hotkey registered!");
while (true)
Thread.Sleep (60000);
if (!IsDriveInUse ())
ShutDownDrive (true);
private static bool IsDriveInUse () => DriveManager.IsDriveInUse ($@"DRIVE_LETTER:\");
private static void InitializeHotKey ()
HotKeyManager.RegisterHotKey (Keys.D, KeyModifiers.Alt | KeyModifiers.Control);
HotKeyManager.HotKeyPressed += HotKeyPressed;
private static void HotKeyPressed (object sender, HotKeyEventArgs hotKeyEventArgs) => ShutDownDrive (true);
private static void ShutDownDrive (bool withDialog = false)
Process process;
(process = new Process
StartInfo = new ProcessStartInfo
WindowStyle = ProcessWindowStyle.Hidden,
FileName = PROGRAM_PATH,
Arguments = string.Format (ARGUMENTS_SHUTDOWN, DRIVE_LETTER)
).Start ();
process.WaitForExit ();
process.Close ();
if (withDialog)
Console.WriteLine ("Drive shut down!");
【问题讨论】:
具体说明“使用中”和“准备就绪”的含义。磁盘可以通过调度一次执行多项操作。在工作站以及服务器硬盘上,几乎总是在进行读取或写入。你到底想解决什么问题?它是固定在机器中的驱动器、可移动驱动器还是网络驱动器? 还假设您可以获得有关“InUse”的正确信息。在您采取行动之前,其状态可能会发生变化。 @L.B 因为我主要是为我编写这个工具,所以我可以向你保证不会出现这种情况,因为我不经常使用我的硬盘。 认为你需要FSCTL_LOCK_VOLUME
- 如果卷上有任何打开的文件,此操作将失败。反之,此操作成功表示没有打开文件。
@RbMm 这对于习惯于 P/Invoke 的人来说可能很明显,但是您能提供一个使用示例吗?
【参考方案1】:
也许您可以使用与您的驱动器相关的 Windows 性能计数器? “磁盘读取/秒”似乎与您的想法非常相关。
在 .Net 中,计数器可通过 System.Diagnostics.PerformanceCounter 看那里 : https://msdn.microsoft.com/en-us/library/system.diagnostics.performancecounter(v=vs.110).aspx
【讨论】:
以上是关于评估驱动器是不是正在使用中的主要内容,如果未能解决你的问题,请参考以下文章
格盘的时候出现“驱动器正在使用中。另一个程序或进程正在使用此驱动器。是不是仍要对其进行格式化”