Практическое руководство. Сохранение часовых поясов во внедренном ресурсе
Для приложения с поддержкой часового пояса часто требуется наличие определенного часового пояса. Тем не менее, поскольку доступность отдельных TimeZoneInfo объектов зависит от информации, хранящейся в реестре локальной системы, даже обычно доступные часовые пояса могут быть отсутствуют. Кроме того, сведения о пользовательских часовых поясах, созданных с помощью CreateCustomTimeZone метода, не хранятся с другими сведениями часового пояса в реестре. Чтобы обеспечить доступность этих часовых поясов при необходимости, их можно сохранить путем сериализации и последующего восстановления путем десериализации.
Как правило, сериализация TimeZoneInfo объекта происходит отдельно от приложения с поддержкой часового пояса. В зависимости от хранилища данных, используемого для хранения сериализованных TimeZoneInfo объектов, данные часового пояса могут быть сериализованы в рамках процедуры установки или установки (например, при хранении данных в разделе приложения реестра) или в рамках подпрограммы служебной программы, которая выполняется до компиляции окончательного приложения (например, при хранении сериализованных данных в файле XML-ресурса .NET (resx).
Помимо файла ресурсов, скомпилированного с помощью приложения, для сведений часового пояса можно использовать несколько других хранилищ данных. следующие основные параметры.
Реестр. Обратите внимание, что приложение должно использовать вложенные ключи собственного ключа приложения для хранения пользовательских данных часового пояса, а не с помощью подразделов HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zone.
Файлы конфигурации.
Другие системные файлы.
Сохранение часового пояса путем сериализации его в RESX-файл
Получение существующего часового пояса или создание нового часового пояса.
Сведения о получении существующего часового пояса см. в статье "Практическое руководство. Доступ к предопределенным объектам UTC и локальным часовым поясам" и " Практическое руководство. Создание экземпляра объекта TimeZoneInfo".
Чтобы создать новый часовой пояс, вызовите одну из перегрузок CreateCustomTimeZone метода. Дополнительные сведения см. в разделе "Практическое руководство . Создание часовых поясов без правил корректировки и практическое руководство. Создание часовых поясов с правилами корректировки".
ToSerializedString Вызовите метод для создания строки, содержащей данные часового пояса.
Создайте StreamWriter экземпляр объекта, указав имя и при необходимости путь resx-файла к конструктору StreamWriter класса.
Создайте ResXResourceWriter экземпляр объекта, передав StreamWriter объект конструктору ResXResourceWriter класса.
Передайте сериализованную строку часового пояса в ResXResourceWriter.AddResource метод.
Вызовите метод ResXResourceWriter.Generate .
Вызовите метод ResXResourceWriter.Close .
StreamWriter Закройте объект, вызвав его Close метод.
Добавьте созданный RESX-файл в проект Visual Studio приложения.
Используя окно свойств в Visual Studio, убедитесь, что для свойства действия сборки RESX-файла задано значение Embedded Resource.
Пример
В следующем примере сериализуется TimeZoneInfo объект, представляющий центральное стандартное время и TimeZoneInfo объект, представляющий станцию Палмера, время Антарктиды в XML-файл ресурса .NET, который называется SerializedTimeZones.resx. Центральное стандартное время обычно определяется в реестре; Палмер станции, Антарктида является пользовательским часовом поясом.
TimeZoneSerialization()
{
TextWriter writeStream;
Dictionary<string, string> resources = new Dictionary<string, string>();
// Determine if .resx file exists
if (File.Exists(resxName))
{
// Open reader
TextReader readStream = new StreamReader(resxName);
ResXResourceReader resReader = new ResXResourceReader(readStream);
foreach (DictionaryEntry item in resReader)
{
if (! (((string) item.Key) == "CentralStandardTime" ||
((string) item.Key) == "PalmerStandardTime" ))
resources.Add((string)item.Key, (string) item.Value);
}
readStream.Close();
// Delete file, since write method creates duplicate xml headers
File.Delete(resxName);
}
// Open stream to write to .resx file
try
{
writeStream = new StreamWriter(resxName, true);
}
catch (FileNotFoundException e)
{
// Handle failure to find file
Console.WriteLine("{0}: The file {1} could not be found.", e.GetType().Name, resxName);
return;
}
// Get resource writer
ResXResourceWriter resWriter = new ResXResourceWriter(writeStream);
// Add resources from existing file
foreach (KeyValuePair<string, string> item in resources)
{
resWriter.AddResource(item.Key, item.Value);
}
// Serialize Central Standard Time
try
{
TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
resWriter.AddResource(cst.Id.Replace(" ", string.Empty), cst.ToSerializedString());
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("The Central Standard Time zone could not be found.");
}
// Create time zone for Palmer, Antarctica
//
// Define transition times to/from DST
TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0),
10, 2, DayOfWeek.Sunday);
TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0),
3, 2, DayOfWeek.Sunday);
// Define adjustment rule
TimeSpan delta = new TimeSpan(1, 0, 0);
TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1),
DateTime.MaxValue.Date, delta, startTransition, endTransition);
// Create array for adjustment rules
TimeZoneInfo.AdjustmentRule[] adjustments = {adjustment};
// Define other custom time zone arguments
string DisplayName = "(GMT-04:00) Antarctica/Palmer Time";
string standardName = "Palmer Standard Time";
string daylightName = "Palmer Daylight Time";
TimeSpan offset = new TimeSpan(-4, 0, 0);
TimeZoneInfo palmer = TimeZoneInfo.CreateCustomTimeZone(standardName, offset, DisplayName, standardName, daylightName, adjustments);
resWriter.AddResource(palmer.Id.Replace(" ", String.Empty), palmer.ToSerializedString());
// Save changes to .resx file
resWriter.Generate();
resWriter.Close();
writeStream.Close();
}
Private Sub SerializeTimeZones()
Dim writeStream As TextWriter
Dim resources As New Dictionary(Of String, String)
' Determine if .resx file exists
If File.Exists(resxName) Then
' Open reader
Dim readStream As TextReader = New StreamReader(resxName)
Dim resReader As New ResXResourceReader(readStream)
For Each item As DictionaryEntry In resReader
If Not (CStr(item.Key) = "CentralStandardTime" Or _
CStr(item.Key) = "PalmerStandardTime") Then
resources.Add(CStr(item.Key), CStr(item.Value))
End If
Next
readStream.Close()
' Delete file, since write method creates duplicate xml headers
File.Delete(resxName)
End If
' Open stream to write to .resx file
Try
writeStream = New StreamWriter(resxName, True)
Catch e As FileNotFoundException
' Handle failure to find file
Console.WriteLine("{0}: The file {1} could not be found.", e.GetType().Name, resxName)
Exit Sub
End Try
' Get resource writer
Dim resWriter As ResXResourceWriter = New ResXResourceWriter(writeStream)
' Add resources from existing file
For Each item As KeyValuePair(Of String, String) In resources
resWriter.AddResource(item.Key, item.Value)
Next
' Serialize Central Standard Time
Try
Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
resWriter.AddResource(cst.Id.Replace(" ", String.Empty), cst.ToSerializedString())
Catch
Console.WriteLine("The Central Standard Time zone could not be found.")
End Try
' Create time zone for Palmer, Antarctica
'
' Define transition times to/from DST
Dim startTransition As TimeZoneInfo.TransitionTime = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#4:00:00 AM#, 10, 2, DayOfWeek.Sunday)
Dim endTransition As TimeZoneInfo.TransitionTime = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#3:00:00 AM#, 3, 2, DayOfWeek.Sunday)
' Define adjustment rule
Dim delta As TimeSpan = New TimeSpan(1, 0, 0)
Dim adjustment As TimeZoneInfo.AdjustmentRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#10/1/1999#, Date.MaxValue.Date, delta, startTransition, endTransition)
' Create array for adjustment rules
Dim adjustments() As TimeZoneInfo.AdjustmentRule = {adjustment}
' Define other custom time zone arguments
Dim DisplayName As String = "(GMT-04:00) Antarctica/Palmer Time"
Dim standardName As String = "Palmer Standard Time"
Dim daylightName As String = "Palmer Daylight Time"
Dim offset As TimeSpan = New TimeSpan(-4, 0, 0)
Dim palmer As TimeZoneInfo = TimeZoneInfo.CreateCustomTimeZone(standardName, offset, DisplayName, standardName, daylightName, adjustments)
resWriter.AddResource(palmer.Id.Replace(" ", String.Empty), palmer.ToSerializedString())
' Save changes to .resx file
resWriter.Generate()
resWriter.Close()
writeStream.Close()
End Sub
В этом примере сериализуются TimeZoneInfo объекты, чтобы они были доступны в файле ресурсов во время компиляции.
Так как метод ResXResourceWriter.Generate добавляет полные сведения заголовка в ФАЙЛ ресурсов .NET XML, его нельзя использовать для добавления ресурсов в существующий файл. Этот пример обрабатывается путем проверка для файла SerializedTimeZones.resx и, если он существует, сохраняя все ресурсы, отличные от двух сериализованных часовых поясов, в универсальный Dictionary<TKey,TValue> объект. Затем существующий файл удаляется, а существующие ресурсы добавляются в новый файл SerializedTimeZones.resx. В этот файл также добавляются сериализованные данные часового пояса.
Поля ключей (или имени) ресурсов не должны содержать внедренные пробелы. Метод Replace(String, String) вызывается для удаления всех внедренных пробелов в идентификаторах часового пояса перед назначением файлу ресурса.
Компиляция кода
Для этого примера требуются:
Эта ссылка на System.Windows.Forms.dll и System.Core.dll будет добавлена в проект.
Импортируются следующие пространства имен:
using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Reflection; using System.Resources; using System.Windows.Forms;
Imports System.Globalization Imports System.IO Imports System.Reflection Imports System.Resources