Сетевые потоки

Среди областей, в которых особенно наглядно проявляются возможности абстрактной модели потока, особое место занимает пересылка информации в Интернете. Работа с низкоуровневым кодом HTML и XML почти не требует усилий со стороны программиста. Хотя в этом разделе мы сможем дать лишь общее представление об этой важной теме и о задействованных пространствах имен, по крайней мере вы увидите, как потоковая интерпретация сетевых данных реализуется на практике. В рассмотренном ниже примере мы передаем информацию на web-сайт и получаем непосредственный HTML-код новой страницы в качестве результата запроса. Анализ полученного HTML-кода приносит нужную информацию.

Мы не смогли устоять перед искушением: наше маленькое приложение обращается на сайт Amazon.com и возвращает текущие сведения о количестве проданных экземпляров нашей книги. Обобщенный алгоритм выглядит следующим образом:

  1. Создать объект URI (Universal Resource Locator) передачей строкового параметра конструктору класса URI.
  2. Передать объект URI методу Create класса HttpWebRequest, чтобы инициировать выдачу запроса HTTP.
  3. Вызвать метод GetResponse класса HttpWebRequest и получить поток.
  4. Проанализировать полученный поток, содержащий HTML-код, и извлечь из него нужную информацию, для чего необходимо знать структуру страницы. Кстати, это одна из причин, по которым для получения данных удобнее использовать web-службы: если Amazon неожиданно сменит структуру своих страниц, наше приложение перестанет работать.

В данном случае страница генерируется следующей строкой запроса, которая и будет использована для создания объекта URI (в конце строки приведен номер ISBN нашей книги):

http://www.amazon.com/exec/obidos/ASIN/1893115992

Следующий конструктор создает экземпляр класса с номером ISBN, переданным в виде строкового параметра:

Public Sub New(ByVal ISBN As String)

m_URL ="http://wvM.amazon.com/exec/obidos/ASIN/" & ISBN

End Sub

Доступное только для чтения свойство GetRank нашего класса просто вызывает закрытую функцию, основной код которой приведен в следующих восьми строках:

1 Dim theURL As New URI(m_URL)

2 Dim theRequest As WebRequest

3 theRequest = WebRequest.Create(theURL)

4 Dim theResponse As WebResponse

5 theResponse = theRequest.GetResponse

6 Dim aReader As New StreamReader(theResponse.GetResponseStream())

7 Dim theData As String .

8 theData = aReader.ReadToEnd

В строке 1 создается объект класса URI. В строках 2 и 3 генерируется web-запрос, передаваемый на сайт Amazon.com. Строки 4 и 5 принимают ответ на запрос, а в строке 6 метод GetResponseStream класса Response конструирует объект StreamReader для полученного потока. На этой стадии строковая переменная theData содержит низкоуровневый HTML-код web-страницы нашей книги.

<font face=verdana.arial.helvetica size=-l>

<b>Amazon.com Sales Rank:</b>

5.776

</font><br>

Остается лишь проанализировать переменную theData и извлечь из нее данные о продажах. Для этого мы воспользуемся вспомогательной функцией Analyze:

Private Function Analyze(ByVal theData As String)As Integer

Dim Location As Integer

Location - theData.IndexOf("<b>Amazon.com Sales Rank:</b>")

+ "<b>Amazon.com Sales Rank:</b>".Length

Dim temp As String

Do Until theData.Substring(Location.l) = "<" temp = temp

StheData.Substring(Location.l)

Location += 1

Loop

Return CInt(temp)

End Function

Для анализа строковой переменной также можно воспользоваться классом регулярных выражений из пространства имен System.Text.

Ниже приведен полный код тестового модуля (разумеется, для тестирования вам также понадобится Интернет-соединение):

Option Strict On Imports System.IO Imports System.Net

Module Module1

Sub Main()

Dim myBook As New AmazonRanker("1893115992")

MsgBox("This book's current rank is " & myBook.GetRank)

End Sub

End Module

Public Class AmazonRanker

Private m_URL As String

Private m_Rank As Integer

Public Sub New(ByVal ISBN As String)

m_URL = "http://www.amazon.com/exec/obidos/ASIN/" & ISBN

End Sub

Public Readonly

Property GetRank() As Integer

Get Return ScrapeAmazon()

End Get End Property

Private Function ScrapeAmazon() As Integer Try

Dim theURL As New URI(m_URL)

Dim theRequest As WebRequest

theRequest = WebRequest.Create(theURL)

Dim theResponse As WebResponse

theResponse = theRequest.GetResponse

DimaReaderAsNew

StreamReader(theResponse.GetResponseStream())

Dim theData As String

theData = aReader.ReadToEnd

Return Analyze(theData) Catch E As Exception

Console.WriteLine(E.StackTrace)

Console. ReadLine()

End Try

End Function

Private Function Analyze(ByVal theData As String) As Integer

Dim Location As Integer

Location = theData.IndexOf("<b>Amazon.com Sales Rank:</b>") + "<b>Amazon.com

Sales Rank:</b>".Length Dim temp As String

Do Until theData.Substring(Location.l) = "<" temp - temp

&theData.Substring(Location,l) Location += 1 Loop

Return CInt(temp)

End Function

End Class

Пример этой программы наглядно показывает, какие неуловимые проблемы порой возникают в результате локализации. Когда наш друг запустил эту программу в Европе, она отказалась работать. Оказалось, что на сайте Amazon по вполне понятным причинам используется американский числовой формат, а программа запускалась в европейской версии Windows, в результате чего символ «,» интерпретировался неверно. Разумеется, проблема легко решается — достаточно, чтобы функция возвращала значение строкового типа.

 

Монитор файловой системы

К числу принципиальных новшеств, отличающих VB .NET от предыдущих версий VB, относится и возможность сделать на сервере то, что в VB давно делалось для клиентов. Речь идет об инкапсуляции общей функциональности в элементах и многократном использовании кода. В завершение этой главы мы покажем, как использовать класс FileSystemMonitor для написания программы, которая отслеживает изменения в заданном каталоге и сигнализирует о них при помощи событий.

Программа может следить за каталогом или набором файлов, соответствующих заданному фильтру. Элемент Fil eSystemMoni tor даже может произвести рекурсивный перебор всех подкаталогов заданного каталога. Инициируемые события перечислены в табл. 9.13.

Таблица 9.13. События монитора файловой системы

Событие

Описание

Changed

Изменения в размере, системных атрибутах, времени последней записи, времени последнего обращения или привилегиях безопасности для подкаталога или файла

Created

Создание подкаталога или файла

Deleted

Удаление подкаталога или файла

Renamed

Переименование подкаталога или файла

Впрочем, компонент FileSystemMonitor не всесилен — в частности, он не позволяет отслеживать изменения в самом каталоге. Если кто-то переименует файл, находящийся в каталоге, вы об этом узнаете, однако переименование самого каталога останется незамеченным (конечно, для отслеживания подобных изменений можно дополнительно следить за родительским каталогом).

Компонент Fi1eSystemMoni tor, как и все компоненты разных панелей элементов VS .NET, является конкретной реализацией более общего класса. В данном случае это класс FileSystemWatcher, производный от класса Component. Режим отслеживания подкаталогов включается следующей командой:

FileSystemWatcherl.IncludeSubdirectohes = True

На рис. 9.6 изображен примерный вид формы. Компонент FileSystemWatcher находится на вкладке Components. Визуального интерфейса он не имеет и поэтому при размещении на форме он отображается на служебной панели, показанной в нижней части рис. 9.6.

Монитор активизируется следующей несложной процедурой:

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

ByVal e As System.EventArgs)Handles btnStart.Click

If CheckPath()Then

FileSystemWatcherl.Path = txtDirectory.Text

FileSystemWatcherl.IncludeSubdirectories = chkRecursive.Checked

FileSystemWatcherl.EnableRaisingEvents = True

End If

End Sub

Для пущей надежности мы убеждаемся в том, что заданный каталог существует. При проверке используется класс Directory, поэтому программа должна импортировать пространство имен System. 10:

Function CheckPath()As Boolean

If Directory.Exists(txtDirectory.Text) Then

Return (True) Else

txtDirectory.Text= "" txtDirectory.Focus 0

MsgBox("No directory by that name exists!") Return False

End If End Function

Рис. 9.6. Пример использования компонента FileSystemWatcher

VB .NET автоматически подключает обработчик события. В следующем фрагменте при изменениях в заданном каталоге вызывается окно сообщения:

Private Sub FileSystemWatcherl_Changed(ByVal sender As Object.

ByVal e As System.IO.FileSystemEventArgs) Handles

FileSystemWatcher1.Changed

MsgBox(txtDirectory.Text & "has changed!")

End Sub

К сожалению, мы не сможем полностью описать этот замечательный компонент. Но прежде, чем вы перейдете к самостоятельным исследованиям, примите к сведению пару полезных советов:

Если вам потребуется более точный контроль, обратитесь к описанию свойства NotifyFilter в электронной документации. Его значение задается в виде констант перечисляемого типа, объединенных оператором Ог, и определяет типы отслежи-

ваемых изменениях. Например, можно отслеживать изменения атрибутов, имени и размера файла.

Без задания свойств Filter и NotifyFilter программа, осуществляющая рекурсивный мониторинг активного или корневого каталога, становится практически бесполезной — событие Changed будет слишком часто срабатывать в результате обычных служебных операций Windows.

 

теплицы

рассвет-юг.рф