解读Silverlight中独立存储

独立存储(Isolated Storage)是Silverlight 2中提供的一个客户端安全的存储,它是一个与Cookie机制类似的局部信任机制。独立存储机制的APIs 提供了一个虚拟的文件系统和可以访问这个虚拟文件系统的数据流对象。Silverlight中的独立存储是基于 .NET Framework中的独立存储来建立的,所以它仅仅是.NET Framework中独立存储的一个子集。

  Silverlight中的独立存储有以下一些特征:

  1.每个基于Silverlight的应用程序都被分配了属于它自己的一部分存储空间,但是应用程序中的程序集却是在存储空间中共享的。一个应用程序被服务器赋给了一个唯一的固定的标识值。基于Silverlight的应用程序的虚拟文件系统现在就以一个标识值的方式来访问了。这个标识值必须是一个常量,这样每次应用程序运行时才可以找到这个共享的位置。

  2.独立存储的APIs 其实和其它的文件操作APIs类似,比如 File 和 Directory 这些用来访问和维护文件文件夹的类。 它们都是基于FileStream APIs 来维护文件内容的。

  3.独立存储严格的限制了应用程序可以存储的数据的大小,目前的上限是每个应用程序为1 MB。

  使用独立存储

  Silverlight中的独立存储功能通过密封类IsolatedStorageFile来提供,位于命名空间System.IO.IsolatedStorag中,IsolatedStorageFile类抽象了独立存储的虚拟文件系统。创建一个 IsolatedStorageFile 类的实例,可以使用它对文件文件夹进行列举或管理。同样还可以使用该类的 IsolatedStorageFileStream 对象来管理文件内容,它的定义大概如下所示:

Silverlight 2中的独立存储

在Silverlight 2中支持两种方式的独立存储,即按应用程序存储或者按站点存储,可以分别使用GetUserStoreForApplication方法和GetUserStoreForSite方法获取IsolatedStorageFile对象。下面看一个简单的示例,最终的效果如下图所示:

Silverlight 2


  下面来看各个功能的实现:

  创建目录,直接使用CreateDirectory方法就可以了,另外还可以使用DirectoryExistes方法来判断目录是否已经存在:

void btnCreateDirectory_Click(object sender,RoutedEventArgs e)
{
using (IsolatedStorageFile store =
IsolatedStorageFile.GetUserStoreForApplication())
{
String directoryName = this.txtDirectoryName.Text;
if (this.lstDirectories.SelectedItem != null)
{
directoryName = System.IO.Path.Combine(this.lstDirectories.SelectedItem.ToString(),
directoryName);
}

if (!store.DirectoryExists(directoryName))
{
store.CreateDirectory(directoryName);
HtmlPage.Window.Alert("创建目录成功!");
}
}
}

  创建文件,通过CreateFile方法获取一个IsolatedStorageFileStream,并将内容写入到文件中:

void btnCreateFile_Click(object sender,RoutedEventArgs e)
{
if (this.lstDirectories.SelectedItem == null &&
this.txtDirectoryName.Text == "")
{
HtmlPage.Window.Alert("请先选择一个目录或者输入目录名");
return;
}
using (IsolatedStorageFile store =
IsolatedStorageFile.GetUserStoreForApplication())
{
String filePath;
if (this.lstDirectories.SelectedItem == null)
{
filePath = System.IO.Path.Combine(this.txtDirectoryName.Text,
this.txtFileName.Text + ".txt");
}
else
{
filePath = System.IO.Path.Combine(this.lstDirectories.SelectedItem.ToString(),
this.txtFileName.Text + ".txt");
}

IsolatedStorageFileStream fileStream = store.CreateFile(filePath);
using (StreamWriter sw = new StreamWriter(fileStream))
{
sw.WriteLine(this.txtFileContent.Text);
}
fileStream.Close();
HtmlPage.Window.Alert("写入文件成功!");
}
}

  读取文件,直接使用System.IO命名空间下的StreamReader:

void btnReadFile_Click(object sender,RoutedEventArgs e)
{
if (this.lstDirectories.SelectedItem == null   
this.lstFiles.SelectedItem == null)
{
HtmlPage.Window.Alert("请先选择目录和文件!");
return;
}
using (IsolatedStorageFile store =
IsolatedStorageFile.GetUserStoreForApplication())
{
String filePath = System.IO.Path.Combine(this.lstDirectories.SelectedItem.ToString(),
this.lstFiles.SelectedItem.ToString());
if (store.FileExists(filePath))
{
StreamReader reader = new StreamReader(store.OpenFile(filePath,
FileMode.Open,FileAccess.Read));
this.txtFileContent.Text = reader.ReadToEnd();

this.txtDirectoryName.Text = this.lstDirectories.SelectedItem.ToString();
this.txtFileName.Text = this.lstFiles.SelectedItem.ToString();
}
}
}

  删除目录和文件

void btnDeleteFile_Click(object sender,RoutedEventArgs e)
{
if (this.lstDirectories.SelectedItem != null &&
this.lstFiles.SelectedItem != null)
{
using (IsolatedStorageFile store =
IsolatedStorageFile.GetUserStoreForApplication())
{
String filePath = System.IO.Path.Combine(this.lstDirectories.SelectedItem.ToString(),
this.lstFiles.SelectedItem.ToString());
store.DeleteFile(filePath);
HtmlPage.Window.Alert("删除文件成功!");
}
}
}

void btnDeleteDirectory_Click(object sender,RoutedEventArgs e)
{
if (this.lstDirectories.SelectedItem != null)
{
using (IsolatedStorageFile store =
IsolatedStorageFile.GetUserStoreForApplication())
{
store.DeleteDirectory(this.lstDirectories.SelectedItem.ToString());
HtmlPage.Window.Alert("删除目录成功!");
}
}
}

  获取目录列表和文件列表:

void lstDirectories_SelectionChanged(object sender,SelectionChangedEventArgs e)
{
if (lstDirectories.SelectedItem != null)
{
using (IsolatedStorageFile store =
IsolatedStorageFile.GetUserStoreForApplication())
{
String[] files = store.GetFileNames(
this.lstDirectories.SelectedItem.ToString() + "/");
this.lstFiles.ItemsSource = files;
}
}
}

void BindDirectories()
{
using (IsolatedStorageFile store =
IsolatedStorageFile.GetUserStoreForApplication())
{
String[] directories = store.GetDirectoryNames("*");
this.lstDirectories.ItemsSource = directories;
}
}
 
例子2
 
在磁盘上写Log
        private void WriteLog(string str)
        {
            string fileName = @"MyLog.txt";
            using (IsolatedStorageFile store = 
            IsolatedStorageFile.GetUserStoreForApplication())
            {
                IsolatedStorageFileStream fileStream;
                if (!store.FileExists(fileName))
                {
                    fileStream = store.CreateFile(fileName);
                }
                else
                {
                    fileStream = store.OpenFile(fileName,FileMode.Append,FileAccess.Write);
                }
                using (StreamWriter sw = new StreamWriter(fileStream))
                {
                    sw.WriteLine("aa");
                }
                fileStream.Close();
            }
        }
 
 


  增加配额

  在本文一开始我就提到独立存储严格的限制了应用程序可以存储的数据的大小,但是我们可以通过IsolatedStorageFile类提供的IncreaseQuotaTo方法来申请更大的存储空间,空间的大小是用字节作为单位来表示的,如下代码片段所示,申请独立存储空间增加到5M:

using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
long newQuetaSize = 5242880;
long curAvail = store.AvailableFreeSpace;

if (curAvail < newQuetaSize)
{
store.IncreaseQuotaTo(newQuetaSize);
}
}
 
当我们试图增加空间大小时浏览器将会弹出一个确认对话框,供我们确认是否允许增加独立存储的空间大小。

  文件被存往何处

  既然独立独立存储是存放在客户端本地,那到底存放在何处呢?在我个人计算机上的地址为:C:\Documents and Settings\XXXUser\Local Settings\Application Data\Microsoft\Silverlight\is\4phkeoqx.b4f\nejnfinr.qiw\1,不同机器会有一些变化,另外在XP下的存储位置与Vista是不相同的。在g文件夹下面,我们找到当前应用程序的一些公有信息,可以看到有如下三个文件

Silverlight


id.dat记录了当前应用程序的ID

quota.dat记录了当前应用程序独立存储的配额,即存储空间大小

Silverlight


used.dat记录已经使用的空间

  在另一个s文件夹下可以找到我们创建的目录以及文件,并且可以打开文件来看到存储的内容,如下图所示:

Silverlight


  禁用独立存储

  现在我们来思考一个问题,既然独立存储是一个与Cookie机制类似的局部信任机制,我们是否也可以禁用独立存储呢?答案自然是肯定的。在Silverlight应用程序上点击右键时,选择Silverlight Configuration菜单,将会看到如下窗口:

Silverlight


  在这里我们可以看到每一个应用程序存储空间的大小以及当前使用的空间;可以删除应用程序独立存储数据或者禁用独立存储的功能

  独立存储配置

  最后在简单说一下独立存储配置,在Beta 1时代是应用程序配置,现在不仅支持应用程序配置,同时还支持站点配置,我们可以用它来存储应用程序配置如每个页面显示图片数量页面布局自定义配置等等,使用IsolatedStorageSettings类来实现,该类在设计时使用了字典来存储名-值对,它的使用相当简单:

IsolatedStorageSettings appSettings =
IsolatedStorageSettings.ApplicationSettings;

appSettings.Add("mykey","myValue");
appSettings.Save();

IsolatedStorageSettings siteSettings =
IsolatedStorageSettings.SiteSettings;
siteSettings.Add("mykey1","myValue1");
siteSettings.Save();

  独立存储配置的机制与我们上面讲的一样,它也是基于本地文件存储,系统认的会创建一个名为__LocalSettings的文件进行存储,如下图所示:

LocalSettings


  打开文件后可以看到,存储的内容(此处进行了整理)

<ArrayOfkeyvalueOfstringanyType
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
keyvalueOfstringanyType>
<Key>mykey</Key>
<Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema"
i:type="d3p1:string">myValue</Value>
</keyvalueOfstringanyType>
</ArrayOfkeyvalueOfstringanyType>

  值得一提的是使用独立存储配置不仅仅可以存储简单类型的数据,也可以存储我们自定义类型的数据
 
 
 

 Silverlight 4.0开始加入了System.Windows.Clipboard(剪切板操作)类,有了它我们就可以非常方便的操作剪切板的数据了,这让一些 Silverlight应用程序中的文本可以copY到Clipboard之中,同时你可以将从其它来源copY到剪切板中的内容粘贴到 Silverlight应用程序之中,在此之前我们只能通过JavaScript来访问剪切板。

     接下来我们看一下Clipboard类为我们带来了什么,Clipboard类支持ContainsText、SetText和GetText三个方法,其中ContainsText可以返回一个bool类型的值,让我们知道剪切板目前保存的类型是否是Silverlight所支持的Unicode类型字符,SetText和GetText分别是用来设置和获GetText剪切板的文本数据。

下面我们看一个Silverlight操作剪切板的实例:

XAML:

1     <Grid x:Name="LayoutRoot" Width="400" Height="200" Background="White">
2          <Grid.RowDeFinitions>
3              <RowDeFinition/>
4              <RowDeFinition/>
5          </Grid.RowDeFinitions>
6          <Grid.ColumnDeFinitions>
7              <ColumnDeFinition />
8              <ColumnDeFinition Width="100"/>
9          </Grid.ColumnDeFinitions>
10         <TextBox x:Name="tbcopy" Width="260" Height="30"/>
11         <TextBox x:Name="tbPaste" Width="260" Height="30" Grid.Row="1"/>
12         <Button Content="复制" Grid.Column="1"
13             Click="btncopy_Click"
14             x:Name="btncopy" Width="80" Height="25"/>
15         <Button Content="粘贴" Grid.Column="1" Grid.Row="1" 
16             Click="btnPaste_Click"
17             x:Name="btnPaste" Width="80" Height="25"/>
18     </Grid>
 
C#:

1          private void btncopy_Click(object sender,RoutedEventArgs e)
2          {
3              if (tbcopy.Text != string.Empty)
4              {
5                  //设置剪切板
6                  Clipboard.SetText(tbcopy.Text);
7              }
8          }

10         private void btnPaste_Click(object sender,RoutedEventArgs e)
11         {
12             //判断剪切板是否包括文本字符
13             if (Clipboard.ContainsText())
14             {
15                 //获取剪切板
16                 tbPaste.Text = Clipboard.GetText();
17             }
18         }
 
运行结果如图所示。

image

第一次运行SetText会让用户确认是否允许Silverlight操作剪切板,如果用户点击否会引发Clipboard access is not allowed异常。

image

下图完成粘贴(Paste)操作。

 

 

 

image

      需要注意的是Silverlight与WPF不同的是,Silverlight仅仅支持Unicode字符类型的剪切板操作,还不能像WPF那像可以对不同的类型的剪切板操作,尽管如此,但是至少是Silverlight技术的一个增强,正是这种不断的进步使更多的理想在Silverlight中变为可能。

相关文章

如何在Silverlight4(XAML)中绑定IsEnabled属性?我试过简单的...
我正在编写我的第一个vb.net应用程序(但我也会在这里标记c#,...
ProcessFile()是在UIThread上运行还是在单独的线程上运行.如...
我从同行那里听说,对sharepoint的了解对职业生涯有益.我们不...
我正在尝试保存一个类我的类对象的集合.我收到一个错误说明:...
我需要根据Silverlight中的某些配置值设置给定控件的Style.我...