412 000 произведений, 108 200 авторов.

Электронная библиотека книг » Иво Салмре » Программирование мобильных устройств на платформе .NET Compact Framework » Текст книги (страница 64)
Программирование мобильных устройств на платформе .NET Compact Framework
  • Текст добавлен: 18 июля 2025, 02:31

Текст книги "Программирование мобильных устройств на платформе .NET Compact Framework"


Автор книги: Иво Салмре



сообщить о нарушении

Текущая страница: 64 (всего у книги 69 страниц)

  total_result = ""

  'Выполнять цикл до максимального значения x_counter, каждый раз

  'присоединяя очередную тестовую строку к рабочей строке

  Dim x_counter As Integer

  For x_counter = 1 To COUNT_UNTIL

   total_result = total_result + numberToStore.ToString() + ", "

   'Увеличить значение счетчика

   numberToStore = numberToStore + 1

  Next

 Next

 PerformanceSampling.StopSample(0)

 'Отобразить длину строки

 MsgBox("String Length: " + total_result.Length.ToString())

 'Отобразить строку

 MsgBox("String : " + total_result)

 'Отобразить длительность интервала времени, ушедшего на вычисления

 MsgBox(PerformanceSampling.GetSampleDurationText(0))

End Sub

'–

'ГОРАЗДО БОЛЕЕ ЭФФЕКТИВНЫЙ АЛГОРИТМ!

'Для имитации создания типичного набора строк используется

'конструктор строк (String Builder)

'–

Private Sub Button2_Click(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) Handles Button2.Click

 'Вызвать сборщик мусора, чтобы тест

 'начинался с чистого состояния.

 'ПРИБЕГАЙТЕ К ЭТОЙ МЕРЕ ТОЛЬКО В ЦЕЛЯХ ТЕСТИРОВАНИЯ! Вызовы

 'сборщика мусора в программах вручную будут приводить к снижению

 'общей производительности приложений!

 System.GC.Collect()

 Dim sb As System.Text.StringBuilder = _

  New System.Text.StringBuilder

 Dim total_result As String

 Dim numberToStore As Integer

 PerformanceSampling.StartSample(1, "StringBuilder")

 Dim outer_loop As Integer

 For outer_loop = 1 To LOOP_ITERATIONS

  'Очистить конструктор строк

  sb.Length = 0

  'Очистить строку со старым результатом

  total_result = ""

  'Выполнять цикл до максимального значения x_counter, каждый раз

  'присоединяя очередную тестовую строку к рабочей строке

  Dim x_counter As Integer

  For x_counter = 1 To COUNT_UNTIL

   sb.Append(numberToStore)

   sb.Append(", ")

   'Увеличить значение счетчика

   numberToStore = numberToStore + 1

  Next

  'Имитируем выполнение некоторых операций над строкой...

  total_result = sb.ToString()

 Next

 PerformanceSampling StopSample(1)

 'Отобразить длину строки

 MsgBox("Длина строки: " + total_result.Length.ToString())

 'Отобразить строку

 MsgBox("String : " + total_result)

 'Отобразить длительность интервала времени, ушедшего на вычисления

 MsgBox(PerformanceSampling.GetSampleDurationText(1))

End Sub

Примеры к главе 9 (производительность и многопоточное выполнение)
Листинг 9.1. Код для управления выполнением одиночной задачи фоновым потоком

Option Strict On

Imports System

Public Class ThreadExecuteTask

'Перечисляем возможные состояния

Public Enum ProcessingState

 '–

 'Начальное состояние

 '–

 'Перечисляем возможные состояния

  notYetStarted

 '–

 'Рабочие состояния

 '–

 'Ожидание запуска фонового потока

 waitingToStartAsync

 'Выполнение кода в фоновом потоке

 running

 'Запросить отмену выполнения вычислений

 requestAbort

 '–

 'Состояния завершения

 '–

 'Состояние завершения: выполнение фонового потока

 'успешно завершено

 done

 'Состояние завершения: выполнение потока отменено

 'до его завершения

 aborted

End Enum

Private m_processingState As ProcessingState

Public Delegate Sub ExecuteMeOnAnotherThread(_

 ByVal checkForAborts As ThreadExecuteTask)

Private m_CallFunction As ExecuteMeOnAnotherThread

Private m_useForStateMachineLock As Object

Public Sub New(ByVal functionToCall As ExecuteMeOnAnotherThread)

 'Создать объект, который мы можем использовать в конечном автомате

 'в целях блокировки

 m_useForStateMachineLock = New Object

 'Обозначить готовность к началу выполнения

 m_processingState = ProcessingState.notYetStarted

 'Сохранить функцию, которую необходимо вызвать

 'в новом потоке

 m CallFunction = functionToCall

 '–

 'Создать новый поток и вызвать в нем функцию на выполнение:

 ' this.ThreadStartPoint()

 '–

 Dim threadStart As System.Threading.ThreadStart threadStart = _

  New System.Threading.ThreadStart(AddressOf ThreadStartPoint)

 Dim newThread As System.Threading.Thread

 newThread = New System.Threading.Thread(threadStart)

 'Обозначить готовность к началу выполнения (в целях определенности

 'это важно сделать еще до того, как будет запущен поток!)

 setProcessingState(ProcessingState.waitingToStartAsync)

 'Дать ОС команду начать выполнение нового потока в асинхронном режиме

 newThread.Start()

 'Возвратить управление функции, вызывающей этот поток

End Sub

'–

'Эта функция является точкой входа, вызываемой для

'выполнения в новом потоке

'–

Private Sub ThreadStartPoint()

 'Установить состояние обработки, соответствующее выполнению

 'функции в новом потоке!

 setProcessingState(ProcessingState.running)

 'Запустить на выполнение пользовательский код и передать указатель в наш

 'класс, чтобы этот код мог периодически проверять, не поступил ли запрос

 'на прекращение выполнения

 m_CallFunction (Me)

 'Если выполнение не было отменено, изменить состояние таким образом,

 'чтобы оно соответствовало успешному завершению

 If (m_processingState <> ProcessingState.aborted) Then

  'Обозначить завершение выполнения

  setProcessingState(ProcessingState.done)

 End If

 'Выйти из потока...

End Sub

'–

'Конечный автомат

'–

Public Sub setProcessingState(ByVal nextState As _

 ProcessingState)

 'В любой момент времени только одному потоку выполнения могут быть

 'разрешены попытки изменить состояние

 SyncLock (m_useForStateMachineLock)

  'В случае попытки повторного вхождения в текущее состояние

  'никакие дополнительные действия не выполняются

  If (m_processingState = nextState) Then

   Return

  End If

  '–

  'Простейший защитный код, гарантирующий

  'невозможность перехода в другое состояние, если задача либо

  'успешно завершена, либо успешно отменена

  '–

  If ((m_processingState = ProcessingState.aborted) OrElse _

   (m_processingState = ProcessingState.done)) Then

   Return

  End If

  'Убедиться в допустимости данного изменения состояния

  Select Case (nextState)

  Case ProcessingState.notYetStarted

   Throw New Exception _

    ("Переход в состояние 'notYetStarted' невозможен")

  Case ProcessingState.waitingToStartAsync

   If (m_processingState <> ProcessingState.notYetStarted) Then

    Throw New Exception("Недопустимое изменение состояния")

   End If

  Case ProcessingState.running

   If (m_processingState <> _

    ProcessingState.waitingToStartAsync) Then

    Throw New Ехсерtion("Недопустимое изменение состояния")

   End If

  Case ProcessingState.done

   'Мы можем завершить работу лишь тогда, когда она выполняется.

   'Это возможно также в тех случаях, когда пользователь затребовал

   'отмену выполнения, но работа к этому моменту уже была закончена

   If ((m_processingState <> ProcessingState.running) AndAlso _

    (m_processingState <> ProcessingState.requestAbort)) Then

    Throw New Exception("Недопустимое изменение состояния")

   End If

  Case ProcessingState.aborted

   If (m_processingState <> ProcessingState.requestAbort) Then

    Throw New Exception("Недопустимое изменение состояния")

   End If

  End Select

  'Разрешить изменение состояния

  m_processingState = nextState

 End SyncLock

End Sub

Public ReadOnly Property State() As ProcessingState

 Get

  Dim currentState As ProcessingState

  'Предотвратить попытки одновременного чтения/записи состояния

  SyncLock (m_useForStateMachineLock)

   currentState = m_orocessingState

  End SyncLock

  Return currentState

 End Get

End Property

End Class

Листинг 9.2. Тестовая программа для выполнения работы в фоновом потоке

Option Strict On

Imports System

'–

'Тестовый код, который используется для выполнения фоновым

'потоком

'–

Public Class Test1

Public m_loopX As Integer

'–

'Функция, вызываемая фоновым потоком

' [in] threadExecute: Класс, управляющий выполнением нашего потока.

' Мы можем контролировать его для проверки

' того, не следует ли прекратить вычисления

'–

Public Sub ThreadEntryPoint(ByVal threadExecute As _

 ThreadExecuteTask)

 'Это окно сообщений будет отображаться в контексте того потока,

 'в котором выполняется задача MsgBox("Выполнение ТЕСТОВОГО ПОТОКА")

 '–

 ' 60 раз

 '–

 For m_loopX = 1 To 60

  'Если затребована отмена выполнения, мы должны завершить задачу

  If (threadExecute.State = _

   ThreadExecuteTask.ProcessingState.requestAbort) Then

   threadExecute.setProcessingState( _

    ThreadExecuteTask.ProcessingState.aborted)

   Return

  End If

  'Имитировать выполнение работы: пауза 1/3 секунды

  System.Threading.Thread.Sleep(333)

 Next

End Sub

End Class

Листинг 9.3. Код для запуска и тестирования приведенного выше тестового кода

'Класс, который будет управлять выполнением нового потока

Private m_threadExecute As ThreadExecuteTask

'Класс, метод которого мы хотим выполнять в асинхронном режиме

Private m_testMe As Test1

'–

'Этот код должен быть запущен ранее другого кода, поскольку он запускает

'новый поток выполнения!

'

'Создать новый поток и обеспечить его выполнение

'–

Private Sub buttonStartAsyncExecution_Click(ByVal sender _

 As System.Object, ByVal e As System.EventArgs) _

 Handles buttonStartAsyncExecution.Click

 'Создать экземпляр класса, метод которого мы хотим вызвать

 'в другом потоке

 m_testMe = New Test1

 'Упаковать точку входа метода класса в делегат

 Dim delegateCallCode As _

  ThreadExecuteTask.ExecuteMeOnAnotherThread

 delegateCallCode = _

  New ThreadExecuteTask.ExecuteMeOnAnotherThread(AddressOf _

  m_testMe.ThreadEntryPoint)

 'Дать команду начать выполнение потока!

 m_threadExecute = New ThreadExecuteTask(delegateCallCode)

End Sub

'Принудительно вызвать запрещенное изменение состояния (это приведет

'к возбуждению исключения)

Private Sub buttonCauseException_Click(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) _

 Handles buttonCauseException.Click

 m_threadExecute.setProcessingState( _

  ThreadExecuteTask.ProcessingState.notYetStarted)

End Sub

'Послать асинхронному коду запрос с требованием отмены его выполнения

Private Sub buttonAbort_Click(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) Handles buttonAbort.Click

 m_threadExecute.setProcessingState( _

  ThreadExecuteTask.ProcessingState.requestAbort)

End Sub

'Проверить состояние выполнения

Private Sub buttonCheckStatus_Click(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) Handles ButtonCheckStatus.Click

 'Запросить у класса управления потоком, в каком состоянии он находится

 MsgBox(m_threadExecute.State.ToString())

 'Запросить класс, метод которого выполняется в потоке,

 'o состоянии выполнения

 MsgBox(m_testMe.m_loopX.ToString())

End Sub

Листинг 9.4. Код, который должен быть помещен в класс Smartphone Form1.cs

'–

'Весь этот код должен находиться внутри класса Form1.cs

'–

'Объект, который будет выполнять все фоновые вычисления

Private m_findNextPrimeNumber As FindNextPrimeNumber

'–

'Обновить текст, информирующий о состоянии...

'–

Sub setCalculationStatusText(ByVal text As String)

 Label1.Text = text

End Sub

Private Sub menuItemExit_Click(ByVal sender As _

 System.Object, ByVal e As System.EventArgs) _

 Handles menuItemExit.Click

 Me.Close()

End Sub

'–

'Пункт меню для начала фоновых вычислений

'–

Private Sub menuItemStart Click(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) _

 Handles menuItemStart.Click

 'Число, с которого мы хотим начать поиск

 Dim startNumber As Long = System.Convert.ToInt64(TextBox1.Text)

 'Установить фоновое выполнение

 m_findNextPrimeNumber = New FindNextPrimeNumber(startNumber)

 'Запустить выполнение задачи в фоновом режиме...

 m_findNextPrimeNumber.findNextHighestPrime_Async()

 'Установить таймер, используемый для контроля длительности вычислений

 Timer1.Interval = 400 '400 мс

 Timer1.Enabled = True

End Sub

'–

'Пункт меню для "отмены" выполняющейся задачи

'–

Private Sub menuItemAbortClick(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) Handles menuItemAbort.Click

 'Не делать ничего, если вычисления не выполняются

 If (m_findNextPrimeNumber Is Nothing) Then Return

 'Установить поток в состояние прекращения выполнения

 m_findNextPrimeNumber.setProcessingState( _

  FindNextPrimeNumber.ProcessingState.requestAbort)

 'Немедленно известить пользователя 'o готовности прекратить выполнение...

 setCalculationStatusText("Ожидание прекращения выполнения...")

End Sub

'–

'Этот таймер, вызываемый потоком пользовательского интерфейса,

'позволяет отслеживать состояние выполнения 'фоновых вычислений

'–

Private Sub Timer1_Tick(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) Handles Timer1.Tick

 'Если к моменту вызова искомое простое число еще

 'не было найдено, отключить таймер

 If (m_findNextPrimeNumber Is Nothing) Then

  Timer1.Enabled = False

  Return

 End If

 '–

 'Если выполнение было отменено, освободить объект,

 'осуществляющий поиск, и выключить таймер

 '–

 If (m_findNextPrimeNumber.getProcessingState = _

  FindNextPrimeNumber.ProcessingState.aborted) Then

  Timer1.Enabled = False

  m_findNextPrimeNumber = Nothing

  setCalculationStatusText("Поиск простого числа отменен")

  Return

 End If

 '–

 'Удалось ли найти правильный ответ?

 '–

 If (m_findNextPrimeNumber.getProcessingState = _

  FindNextPrimeNumber.ProcessingState.foundPrime) Then

  Timer1.Enabled = False

  'Отобразить результат

  setCalculationStatusText("Число найдено! Следующее простое число = " + _

   m_findNextPrimeNumber.getPrime().ToString())

  m_findNextPrimeNumber = Nothing

  Return

 End If

 '–

 'Вычисления продолжаются. Информировать

 'пользователя о состоянии выполнения...

 '–

 'Получить два выходных значения

 Dim numberCalculationsToFar As Long

 Dim currentItem As Long

 m_findNextPrimeNumber.getExecutionProgressInfo( _

  numberCalculationsToFar, currentItem)

 setCalculationStatusText("Вычисления продолжаются. Поиск в области: " + _

  CStr(currentItem) + ". " + _

  "Для вас выполнено " + CStr(numberCalculationsToFar) + _

  " расчетов!")

End Sub

Листинг 9.5. Код класса FindNextPrimeNumber.cs

Option Strict On

Imports System

Public Class FindNextPrimeNumber

'Перечисляем возможные состояния

Public Enum ProcessingState

 notYetStarted

 waitingToStartAsync

 lookingForPrime

 foundPrime

 requestAbort

 aborted

End Enum

Private m_startPoint As Long

Private m_NextHighestPrime As Long

'Поиск какого количества элементов выполнен?

Private m_comparisonsSoFar As Long

'Для какого элемента сейчас выполняется поиск простого числа?

Private m_CurrentNumberBeingExamined As Long

'Вызывается для обновления информации о состоянии выполнения

Public Sub getExecutionProgressInfo( _

 ByRef numberCalculationsSoFar As Long, _

 ByRef currentItemBeingLookedAt As Long)

 'ПРИМЕЧАНИЕ. Мы используем блокирование потока для уверенности в том,

 'что эти значения не считываются во время выполнения операции

 'их записи. Поскольку доступ к m_comparisonsSoFar

 'и m_CurrentNumberBeingExamined могут осуществлять

 'одновременно несколько потоков, любая выполняемая над ними

 'операция записи/считывания должна синхронизироваться с "блокировкой",

 'что будет гарантировать "атомарность" этих операций

 SyncLock (Me)

  numberCalculationsSoFar = m_comparisonsSoFar

  currentItemBeingLookedAt = m_CurrentNumberBeingExamined

 End SyncLock

End Sub

Private m_processingState As ProcessingState

'–

'Простейший конечный автомат

'–

Public Sub setProcessingState(ByVal nextState As _

 ProcessingState)

 'Простейший защитный код, гарантирующий

 'невозможность перехода в другое состояние, если задача

 'либо успешно завершена, либо успешно отменена

 If ((m_processingState = ProcessingState.aborted) _

  OrElse (m_processingState = ProcessingState.foundPrime)) Then

  Return

 End If

 'Разрешить изменение состояния

 m_processingState = nextState

End Sub

Public ReadOnly Property getProcessingState() As ProcessingState

 Get

  Return m_processingState

 End Get

End Property

'–

'Возвращает простое число

'–

Public Function getPrime() As Long

 If (m_processingState <> ProcessingState.foundPrime) Then

  Throw New Exception("Простое число еще не найдено!")

 End If

 Return m_NextHighestPrime

End Function

'Конструктор класса

Public Sub New(ByVal startPoint As Long)

 setProcessingState(ProcessingState.notYetStarted)

 m_startPoint = startPoint

End Sub

'–

'Создает новый рабочий поток, который будет вызывать функцию

'findNextHighestPrime()

'–

Public Sub findNextHighestPrime_Async()

 Dim threadStart As System.Threading.ThreadStart

 threadStart = _

  New System.Threading.ThreadStart(AddressOf _

  findNextHighestPrime)

 Dim newThread As System.Threading.Thread

 newThread = New System.Threading.Thread(threadStart)

 'Состояние должно отвечать, что поиск продолжается

 setProcessingState(ProcessingState.waitingToStartAsync)

 newThread.Start()

End Sub

'–

'Основной рабочий поток. Этот поток запускает поиск очередного

'простого числа и выполняется до тех пор, пока не произойдет

'одно из следующих двух событий:

' (а) найдено очередное простое число

' (b) от внешнего (по отношению к данному) потока поступила

' команда прекратить выполнение

'–

Public Sub findNextHighestPrime()

 'Если поступила команда прекратить выполнение, то поиск даже

 'не должен начинаться

 If (m_processingState = ProcessingState.requestAbort) Then

  GoTo finished_looking

 End If

 'Состояние должно отвечать, что поиск продолжается

 setProcessingState(ProcessingState.lookingForPrime)

 Dim currentItem As Long

 'Проверить, является ли число нечетным

 If ((m_startPoint And 1) = 1) Then

  'Число является нечетным, начать поиск со следующего нечетного числа

  currentItem = m_startPoint + 2

 Else

  'Число является четным, начать поиск со следующего нечетного числа

  currentItem = m_startPoint + 1

 End If

 'Приступить к поиску простого числа

 While (m_processingState = ProcessingState.lookingForPrime)

  'B случае нахождения простого числа, возвратить его

  If (isItemPrime(currentItem) = True) Then

   m_NextHighestPrime = currentItem

   'Обновить состояние

   setProcessingState(ProcessingState.foundPrime)

  End If

  currentItem = currentItem + 2

 End While

finished_looking:

 'Выход. К этому моменту либо от другого потока поступила

 'команда прекратить поиск, либо было найдено и записано

 'следующее наибольшее простое число

 'Если поступил запрос прекратить выполнение,

 'сообщить, что выполнение процесса прекращено

 If (m_processingState = ProcessingState.requestAbort) Then

  setProcessingState(ProcessingState.aborted)

 End If

End Sub

'Вспомогательная функция, которая проверяет, является

'ли число простым

Private Function isItemPrime(ByVal potentialPrime _

 As Long) As Boolean

 'Если число – четное, значит, оно не является простым

 If ((potentialPrime And 1) = 0) Then

  Return False

 End If

 'Продолжать поиск до тех пор, пока не будет превышено значение

 'квадратного корня из числа

 Dim end_point_of_search As Long end_point_of_search = _

  CLng(System.Math.Sqrt(potentialPrime)) + 1

 Dim current_test_item As Long = 3

 While (current_test_item <= end_point_of_search)

  '–

  'Проверить, не поступила ли команда прекратить выполнение!

  '–

  If (m_processingState <> ProcessingState.lookingForPrime) Then

   Return False

  End If

  'Если число делится без остатка,

  'значит, оно не является простым

  If (potentialPrime Mod current_test_item = 0) Then

   Return False

  End If

  'Увеличить число на два

  current_test_item = current test_item + 2

  '–

  'Увеличить число проверенных элементов

  '–

  'ПРИМЕЧАНИЕ. Мы используем блокирование потока для уверенности в том,

  'что эти значения не считываются во время выполнения операции

  'их записи. Поскольку доступ к m_comparisonsSoFar

  'и m_CurrentNumberBeingExamined могут осуществлять

  'одновременно несколько нитей, любая выполняемая над ними

  'операция записи/считывания должна синхронизироваться с "блокировкой",

  'что будет гарантировать "атомарность" этих операций

  SyncLock (Me)

   m_CurrentNumberBeingExamined = potentialPrime

   m_comparisonsSoFar = m_comparisonsSoFar + 1

  End SyncLock

 End While

 'Число является простым

 Return True

End Function

End Class

Примеры к главе 10 (производительность и XML)
Листинг 10.1. Использование XML DOM для сохранения данных в файле и их загрузки

Option Strict On

Option Compare Binary

Imports System

'–

'Демонстрирует сохранение и загрузку файлов с

'использованием объектной модели документа XML

'–

Public Class SaveAndLoadXML_UseDOM

 'XML-дескрипторы, которые мы будем использовать в нашем документе

 Const XML_ROOT_TAG As String = "AllMyData"

 Const XML_USERINFO_TAG As String = "UserInfo"

 Const XML_USERID_TAG As String = "UserID"

 Const XML_NAMEINFO_TAG As String = "Name"

 Const XML_FIRSTNAME _TAG As String = "FirstName"

 Const XML_LASTNAME_TAG As String = "LastName"

 '–

 'Загружает пользовательское состояние

 ' [in] fileName: Имя файла, используемого для сохранения данных

 ' [out] userId: Загруженный идентификатор пользователя

 ' [out] firstName: Загруженное имя пользователя

 ' [out] lastName: Загруженная фамилия пользователя

 '–

 Public Shared Sub XML_LoadUserInfo(ByVal fileName As String, _

  ByRef userId As Integer, ByRef firstName As String, _

  ByRef lastName As String)

 'Начинаем с нулевых значений

 userId = 0

 firstName = ""

 lastName = ""

 'Предполагаем, что данные еще не загружены

 Dim gotUserInfoData As Boolean = False

 Dim xmlDocument As System.Xml.XmlDocument = _

  New System.Xml.XmlDocument

 xmlDocument.Load(fileName)

 'Получить корневой узел

 Dim rootElement As System.Xml.XmlElement

 rootElement = _

  CType(xmlDocument.ChildNodes(0), System.Xml.XmlElement)

 'Убедиться в том, что корневой узел согласуется с ожидаемым текстом,

 'ибо противное означает, что мы имеем дело с каким-то другим XML-файлом

 If (rootElement.Name <> XML_ROOT_TAG) Then

  Throw New Exception("Тип корневого узла не совпадает с ожидаемым!")

 End If

 '–

 'Простой конечный автомат для итеративного обхода всех узлов

 '–

 Dim childOf_RootNode As System.Xml.XmlElement

 For Each childOf_RootNode In _

  rootElement.ChildNodes

  'Если это узел UserInfo, то мы хотим просмотреть его содержимое

  If (childOf_RootNode.Name = XML_USERINFO_TAG) Then

   gotUserInfoData = True

   'Пользовательские данные найдены

   '–

   'Загрузить каждый из подэлементов

   '–

   Dim child_UserDataNode As System.Xml.XmlElement

   For Each child_UserDataNode In _

    childOf_RootNode.ChildNodes

    'Идентификатор пользователя (UserID)

    If (child_UserDataNode.Name = XML_USERID_TAG) Then

     userId = CInt(child_UserDataNode.InnerText)

     'ФИО пользователя (UserName)

    ElseIf (child_UserDataNode.Name = XML_NAMEINFO_TAG) Then

     Dim child_Name As System.Xml.XmlElement

      For Each child_Name In child_UserDataNode.ChildNodes

      'Имя (FirstName)

      If (child_Name.Name = XML_FIRSTNAME_TAG) Then

       firstName = child_Name.InnerText

       'Фамилия (LastName)

      ElseIf (chi1d_Name.Name = XML_LASTNAME_TAG) Then

       lastName = child_Name.InnerText

      End If

     Next 'Конец цикла разбора UserName

    End If 'Конец оператора if, осуществляющего проверку UserName

   Next 'Конец цикла разбора UserInfo

  End If 'Конец оператора if, осуществляющего проверку UserInfo

 Next 'Конец цикла разбора корневого узла

 If (gotUserInfoData = False) Then

  Throw New Exception("Данные пользователя в XML-документе не найдены!")

 End If

End Sub

'–

'Сохраняет пользовательское состояние

' [in] fileName: Имя файла, используемого для сохранения данных

' [in] userId: Идентификатор пользователя, который мы хотим сохранить

' [in] firstName: Имя пользователя, которое мы хотим сохранить

' [in] lastName: Фамилия пользователя, которую мы хотим сохранить

'–

Public Shared Sub XML_SaveUserInfo(ByVal fileName As String, _

 ByVal userId As Integer, ByVal firstName As String, _

 ByVal lastName As String)

 Dim xmlDocument As System.Xml.XmlDocument = _

  New System.Xml.XmlDocument

 '–

 'Добавить элемент документа высшего уровня

 '–

 Dim rootNodeForDocument As System.Xml.XmlElement

 rootNodeForDocument = xmlDocument.CreateElement( _

  XML_ROO T_TAG)

 xmlDocument.AppendChild(rootNodeForDocument)

 '–

 'Добавить данные в элемент UserInfo

 '–

 Dim topNodeForUserData As System.Xml.XmlElement

 topNodeForUserData = xmlDocument.CreateElement( _

  XML_USERINFO_TAG)

 rootNodeForDocument.AppendChild(topNodeForUserData)

 '–

 'Добавить значение UserID в наш документ

 '–

 'Создать подузел для информации о пространстве имен

 Dim subNodeForUserID As System.Xml.XmlElement

 subNodeForUserID = _

  xmlDocument.CreateElement(XML_USERID_TAG)

 subNodeForUserID.InnerText = _

  System.Convert.ToString(userId)

 'Присоединить подузел UserID к узлу высшего уровня

 topNodeForUserData.AppendChild(subNodeForUserID)

 '–

 'Добавить все значения NameInfo в наш документ

 '–

 'Создать подузел для информации о пространстве имен

 Dim subNodeForNameInfo As System.Xml.XmlElement

 subNodeForNameInfo = xmlDocument.CreateElement( _

  XML_NAMEINFO_TAG)

 'Имя (FirstName)

 Dim subNodeFirstName As System.Xml.XmlElement

 subNodeFirstName = xmlDocument.CreateElement( _

  XML_FIRSTNAME TAG)

 subNodeFirstName.InnerText = firstName

 'Фамилия (LastName)

 Dim subNodeLastName As System.Xml.XmlElement

 subNodeLastName = xmlDocument.CreateElement( _

  XML_LASTNAME_TAG)

 subNodeLastName.InnerText = lastName

 'Присоединить подузлы имени и фамилии к родительскому узлу

 'NameInfo

 subNodeForNameInfo.AppendChild(subNodeFirstName)

 subNodeForNameInfo.AppendChild(subNodeLastName)

 'Присоединить подузел NameInfo (вместе с его дочерними узлами)

 'к узлу высшего уровня

 topNodeForUserData.AppendChild(subNodeForNameInfo)

 '–

 'Сохранить документ

 '–

 Try

  xmlDocument.Save(fileName)

 Catch ex As System.Exception

  MsgBox( _

   "Ошибка при сохранении XML-документа – " + ex.Message)

 End Try

End Sub 'Конец функции

End Class 'Конец класса

Листинг 10.2. Вызов кода, предназначенного для сохранения и загрузки XML-документа

Private Sub Button1_Click(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) Handles Button1.Click

 Const FILENAME As String = "TestFileName.XML"

 'Сохранить, используя XML DOM

 SaveAndLoadXML_UseDOM.XML_SaveUserInfo(FILENAME, 14, "Ivo", _

  "Salmre")

 'Сохранить, используя объект однонаправленной записи XMLWriter

 'SaveAndLoadXML_UseReaderWriter.XML_SaveUserInfo(FILENAME, _

 ' 18, "Ivo", "Salmre")

 Dim userID As Integer

 Dim firstName As String

 Dim lastName As String

 'Загрузить, используя XML DOM

 SaveAndLoadXML_UseDOM.XML_LoadUserInfo(FILENAME, userID, _

  firstName, lastName)

 'Загрузить, используя объект однонаправленного чтения XMLReader

 'SaveAndLoadXML_UseReaderWriter.XML_LoadUserInfo(FILENAME, _

 ' userID, firstName, lastName)

 MsgBox("Готово! " + _

  userID.ToString() + ", " + lastName + ", " + firstName)

End Sub

Листинг 10.3. Использование однонаправленного чтения/записи XML-данных для загрузки XML-документа из файла и его сохранения

Option Strict On

Option Compare Binary

Imports System

Public Class SaveAndLoadXML UseReaderWriter

'XML-дескрипторы, которые мы будем использовать в своем документе

Const XML_ROOT_TAG As String = "AllMyData"

Const XML_USERINFO_TAG As String = "UserInfo"

Const XML_USERID_TAG As String = "UserID"

Const XML_NAMEINFO_TAG As String = "Name"

Const XML_FIRSTNAME_TAG As String = "FirstName"

Const XML_LASTNAME TAG As String = "LastName"

'Набор состояний, отслеживаемых по мере чтения данных

Private Enum ReadLocation

 inAllMyData

 inUserInfo

 inUserID

 inName

 inFirstName

 inLastName

End Enum

'–

'Сохраняет пользовательское состояние

' [in] fileName: Имя файла, используемого для сохранения данных

' [in] userId: Идентификатор пользователя, который мы хотим сохранить

' [in] firstName: Имя пользователя, которое мы хотим сохранить

' [in] lastName: Фамилия пользователя, которую мы хотим сохранить

'–

Public Shared Sub XML_SaveUserInfo(ByVal fileName As String, _

 ByVal userId As Integer, ByVal firstName As String, _

 ByVal lastName As String)

 Dim xmlTextWriter As System.Xml.XmlTextWriter

 xmlTextWriter = New System.Xml.XmlTextWriter(fileName, _

  System.Text.Encoding.Default)

 'Записать содержимое документа!

 '

 xmlTextWriter.WriteStartElement(XML_ROOT_TAG)

 '

 xmlTextWriter.WriteStartElement(XML_USERINFO_TAG)

 '

 '

 xmlTextWriter.WriteStartElement(XML_NAMEINFO_TAG)

 '

 xmlTextWriter.WriteStartElement(XML_FIRSTNAME_TAG)

 '

 xmlTextWriter.WriteString(firstName) 'Запись значения

 xmlTextWriter.WriteEndElement() 'Закрыть дескриптор имени

 '

 xmlTextWriter.WriteStartElement(XML_LASTNAME_TAG)

 '

 xmlTextWriter.WriteString(lastName) 'Запись значения

 xmlTextWriter.WriteEndElement() 'Закрыть дескриптор фамилии

 '

 xmlTextWriter.WriteEndElement() 'Закрыть дескриптор ФИО

 '

 '

 xmlTextWriter.WriteStartElement(XML_USERID_TAG)

 '

 'Запись значения

 xmlTextWriter.WriteString(userId.ToString())

 xmlTextWriter.WriteEndElement() 'Закрыть дескриптор UserID

 '

 xmlTextWriter.WriteEndElement()

 'Закрыть дескриптор UserInfo

 '

 xmlTextWriter.WriteEndElement() 'Закрыть дескриптор документа

 xmlTextWriter.Close()

End Sub

'–

'Загружает пользовательское состояние

' [in] fileName: Имя файла, используемого для сохранения данных

' [out] userId: Загруженный идентификатор пользователя

' [out] firstName: Загруженное имя пользователя

' [out] lastName: Загруженная фамилия пользователя

'–

Public Shared Sub XML_LoadUserInfo(ByVal fileName As String, _

 ByRef userId As Integer, ByRef firstName As String, _

 ByRef lastName As String)

 Dim currentReadLocation As ReadLocation

 'Начинаем с нулевых значении

 userId = 0

 firstName = ""

 lastName = ""

 Dim xmlReader As System.Xml.XmlTextReader = _

  New System.Xml.XmlTextReader(fileName)

 xmlReader.WhitespaceHandling = _

  System.Xml.WhitespaceHandling.None

 Dim readSuccess As Boolean

 readSuccess = xmlReader.Read()

 If (readSuccess = False) Then

  Throw New System.Exception("Отсутствуют XML-данные для чтения!")

 End If

 'Убедиться в том, что мы распознали корневой дескриптор

 If (xmlReader.Name <> XML_ROOT_TAG) Then

  Throw New System.Exception( _

   "Корневой дескриптор отличается от ожидаемого!")

 End If

 'Отметить текущее местоположение в документе

 currentReadLocation = ReadLocation.inAllMyData

 '–

 'Цикл прохождения документа и чтение необходимых данных

 '–

 While (readSuccess)

  Select Case (xmlReader.NodeType)

  'Вызывается при входе в новый элемент


    Ваша оценка произведения:

Популярные книги за неделю