2013-06-26 2 views
2

Я пишу программу, которая должна анализировать результат вывода из команды Windows «diskpart», особенно при анализе диска & информацию о томе (с использованием «списка дисков» & «том списка») с VB. NETРазбор вывода Diskpart с .NET

Я сумел использовать выход DISKPART результаты в текстовый файл с помощью командной строки DOS diskpart /s myscript.scp > result.txt

Сейчас в VB.NET Мне нужно разобрать «result.txt», чтобы получить «номер тома», «диск буква ',' метка диска ',' type ',' size '&' size_unit 'в массив для дальнейшей обработки.

Каков наилучший способ извлечения всех этих данных? Я пытаюсь читать в MSDN о регулярных выражениях .NET (Regex), это заставляет меня запутываться и не уверен, что шаблон должен использоваться в моем случае.

Надеюсь, что кто-то может мне помочь, любой альтернативный метод синтаксического анализа приветствуется.

* Обновление 26 июня 2013 г. - по какой-то технической причине мне нужно придерживаться «diskpart» и полагаться на его результаты вывода для синтаксического анализа.

Пример ввода (Result.txt)

Microsoft DiskPart version 6.1.7601 
Copyright (C) 1999-2008 Microsoft Corporation. 
On computer: PC1 

    Disk ### Status   Size  Free  Dyn Gpt 
    -------- ------------- ------- ------- --- --- 
    Disk 0 Online   1863 GB 1024 KB 
    Disk 1 No Media   0 B  0 B 
    Disk 2 Online   7424 MB  0 B 

    Volume ### Ltr Label  Fs  Type  Size  Status  Info 
    ---------- --- ----------- ----- ---------- ------- --------- -------- 
    Volume 0  E      DVD-ROM   0 B No Media 
    Volume 1  C SYSTEM  NTFS Partition 100 GB Healthy System 
    Volume 2  D TEMP   NTFS Partition 1606 GB Healthy Pagefile 
    Volume 3  G      Removable  0 B No Media 
    Volume 4  F GSFKEY  NTFS Removable 7423 MB Healthy 

Выход

disk(0) 
.disknum=0 
.size=1863 
.size_unit="GB 

disk(0) 
.disknum=1 
.size=0 
.size_unit="B" 

..and so on 

vol(0) 
.volnum=0 
.letter="E" 
.label="" 
.type="DVD-ROM" 
.size=0 
.size_unit="B" 

vol(1) 
.volnum=1 
.letter="C" 
.label="SYSTEM" 
.type="Partition" 
.size=100 
.size_unit="GB" 

..and so on 
+1

Является ли техническая причина «Мне нужно, чтобы мой код был хрупким, если они когда-либо меняли выходной формат' d iskpart' "? –

ответ

3

Я бы сначала создать класс, который представляет ваши данные:

Public Class DiskPartResult 
    Public Property Volume As String 
    Public Property Number As Int32 
    Public Property Ltr As String 
    Public Property Label As String 
    Public Property Fs As String 
    Public Property Type As String 
    Public Property SizeUnit As String 
    Public Property Status As String 
    Public Property Info As String 
End Class 

Теперь вы можете использовать File.ReadLines со следующими Linq запрос, чтобы получить соответствующие строки данных:

Dim diskPartFileLines = File.ReadLines("Results.txt") 
Dim dataLines = From line In diskPartFileLines 
       Skip While Not line.TrimStart().StartsWith("----------") Skip (1) 
       Take While line.TrimStart().StartsWith("Volume") 

Теперь вам могут заполнять List(Of DiskPartResult):

Dim alldata = New List(Of DiskPartResult) 
For Each line As String In dataLines 
    Dim columns = line.Trim().Split({vbTab}, StringSplitOptions.RemoveEmptyEntries) 
    If columns.Length <> 9 Then Continue For 
    Dim data = New DiskPartResult() 
    data.Volume = columns(0) 
    data.Number = Int32.Parse(columns(1)) 
    data.Ltr = columns(2) 
    data.Label = columns(3) 
    data.Fs = columns(4) 
    data.Type = columns(5) 
    Dim sizeInfo = columns(6) 
    data.Size = Double.Parse(sizeInfo.Split()(0).Trim()) 
    data.SizeUnit = sizeInfo.Split()(1).Trim() 
    data.Status = columns(7) 
    data.Info = columns(8) 
    alldata.Add(data) 
Next 

Если вы хотите вывести документ:

For Each dpr As DiskPartResult In alldata 
    Console.WriteLine("vol({0})", dpr.Volume) 
    Console.WriteLine(" .volnum={0}", dpr.Number) 
    Console.WriteLine(" .letter={0}", dpr.Ltr) 
    Console.WriteLine(" .label={0}", dpr.Label) 
    Console.WriteLine(" .type={0}", dpr.Type) 
    Console.WriteLine(" .size={0}", dpr.Size) 

    ' and so on ... ' 
Next 

, по-видимому, сепаратор не закладками характер, это все пробелы. Любые идеи?

Затем вы можете «разбить» на индексы с двойным белым пространством, которые вы можете получить из строки заголовка, потому что линии данных используют одни и те же индексы.

Я создал следующий метод расширения, чтобы получить все показатели для данного Seperator строки в тексте:

<System.Runtime.CompilerServices.Extension()> _ 
Public Function AllIndexOf(text As String, str As String, comparisonType As StringComparison) As IList(Of Integer) 
    Dim allIndeces As IList(Of Integer) = New List(Of Integer)() 
    Dim index As Integer = text.IndexOf(str, comparisonType) 
    While index <> -1 
     allIndeces.Add(index) 
     index = text.IndexOf(str, index + str.Length, comparisonType) 
    End While 
    Return allIndeces 
End Function 

Теперь вы можете использовать этот код для запроса необходимые данные:

Dim diskPartFileLines = File.ReadAllLines("Results.txt") 
Dim headerLine = (From line In diskPartFileLines 
        Skip While Not line.TrimStart().StartsWith("----------")).First().Trim() 
Dim colStartIndices As IList(Of Int32) = headerLine.AllIndexOf(" ", StringComparison.OrdinalIgnoreCase) 
Dim dataLines = From line In diskPartFileLines 
       Skip While Not line.TrimStart().StartsWith("----------") Skip 1 
       Take While line.TrimStart().StartsWith("Volume") 
       Select line.Trim() 
Dim alldata = New List(Of DiskPartResult) 

Тогда перечислите запрос, инициализируйте DiskPartResults и добавьте их в список:

For Each line In dataLines 
    Dim data = New DiskPartResult() 
    Dim lastIndex = 0 
    For i As Int32 = 0 To colStartIndices.Count - 1 
     Dim index = colStartIndices(i) 
     Select Case i 
      Case 0 
       data.Volume = line.Substring(lastIndex, index - lastIndex).Trim() 
      Case 1 
       data.Number = Int32.Parse(line.Substring(lastIndex, index - lastIndex).Trim()) 
      Case 2 
       data.Ltr = line.Substring(lastIndex, index - lastIndex).Trim() 
      Case 3 
       data.Label = line.Substring(lastIndex, index - lastIndex).Trim() 
      Case 4 
       data.Fs = line.Substring(lastIndex, index - lastIndex).Trim() 
      Case 5 
       data.Type = line.Substring(lastIndex, index - lastIndex).Trim() 
      Case 6 
       Dim sizeInfo = line.Substring(lastIndex, index - lastIndex).Trim() 
       data.Size = Double.Parse(sizeInfo.Split()(0).Trim()) 
       data.SizeUnit = sizeInfo.Split()(1).Trim() 
      Case 7 
       data.Status = line.Substring(lastIndex, index - lastIndex).Trim() 
      Case 8 
       data.Info = line.Substring(lastIndex, index - lastIndex).Trim() 
     End Select 
     lastIndex = index 
    Next 
Next 

Обратите внимание, что For Each не проверен, но он должен дать вам эту идею.

+0

Если у seperator нет символа табуляции, у вас есть проблема. Потому что трудно обнаружить новый столбец ('String.Split()' будет даже разбивать «Диск 0» на два столбца). –

+0

, очевидно, разделитель не является символом табуляции, это все пробелы. Есть идеи? – Dennis

+0

@ Dennis: Отредактировал мой ответ. –

5

Вы можете получить эту информацию от System.IO.DriveInfo?

public DriveInfo(string driveName); 


    public long AvailableFreeSpace 
    public string DriveFormat 
    public DriveType DriveType 
    public DirectoryInfo RootDirectory 
    public long TotalFreeSpace 
    public long TotalSize 
    public string VolumeLabel 
    public static DriveInfo[] GetDrives(); 
+0

по какой-то технической причине, мне нужно придерживаться рассылки – Dennis

+3

Какова техническая причина? Вам сказали, что «единственный способ сделать это - синтаксический анализ текстового файла»? – Neil

+0

это было требование к дизайну другой командой, скорее всего, потому, что diskpart будет использоваться при выполнении разбиения диска в процессе ... поэтому предоставление правильного и последовательного «номера диска» имеет решающее значение в этом случае – Dennis

1

'Получить номер диска Dim запрос Dim objWMI Dim diskDrives Dim diskDrive Dim перегородки Dim раздел' будет содержать диск & разделов номера Dim logicalDisks Dim LogicalDisk 'будет содержать букву диска Dim stroutput Как New StringBuilder

 objWMI = GetObject("winmgmts:\\.\root\cimv2") 
     diskDrives = objWMI.ExecQuery("SELECT * FROM Win32_DiskDrive") ' First get out the physical drives 
     For Each diskDrive In diskDrives 
      query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + diskDrive.DeviceID + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition" ' link the physical drives to the partitions 
      partitions = objWMI.ExecQuery(query) 
      For Each partition In partitions 
       query = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + partition.DeviceID + "'} WHERE AssocClass = Win32_LogicalDiskToPartition" ' link the partitions to the logical disks 
       logicalDisks = objWMI.ExecQuery(query) 
       For Each logicalDisk In logicalDisks 
        stroutput.Append(logicalDisk.DeviceID & " - " & partition.Caption) 
        ' Wscript.Echo(logicalDisk.DeviceID & " - " & partition.Caption) 
       Next 
      Next 
     Next 
     MessageBox.Show(stroutput.ToString) 
+0

На выходе будут отображаться номера дисков, используемые в Diskpart, а также информация о диске и информация раздела. – MalvaStyle