82、Silverlight文件访问功能全解析

Silverlight文件访问功能全解析

1. 多文件下载与上传

在文件传输方面,有一种方法具有一个不错的副作用,即代码允许用户同时启动多个下载任务。每个下载任务都有自己的 SaveFileDialog 对象,这样在下载完成时,每个任务都能将内容保存到相应的文件中。

上传代码与之类似,但它会显示 OpenFileDialog ,一旦用户选择了文件,就会从文件中检索数据。数据会被放入一个字节数组,然后传递给 UploadFileAsync() 方法。以下是Silverlight客户端实现上传功能的代码:

Private Sub cmdUpload_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim openDialog As New OpenFileDialog()

    If openDialog.ShowDialog() = True Then
        Try
            Using stream As Stream = openDialog.File.OpenRead()
                ' 不允许上传大于5MB的文件
                If stream.Length < 5120000 Then
                    Dim data(stream.Length - 1) As Byte
                    stream.Read(data, 0, stream.Length)

                    client.UploadFileAsync(openDialog.File.Name, data)
                    lblStatus.Text = "Upload started."
                Else
                    lblStatus.Text = "Files must be less than 5 MB."
                End If
            End Using
        Catch
            lblStatus.Text = "Error reading file."
        End Try
    End If
End Sub

Private Sub client_UploadFileCompleted(ByVal sender As Object, _
  ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
    If e.Error Is Nothing Then
        lblStatus.Text = "Upload succeeded."

        ' 刷新文件列表
        client.GetFileListAsync()
    Else
        lblStatus.Text = "Upload failed."
    End If
End Sub

通过上述代码,我们就拥有了一个可以在客户端和Web服务器之间传输内容的完整功能的客户端。

2. 文件拖放功能

OpenFileDialog 类为Silverlight应用程序访问非隔离存储中的文件提供了最实用的方法。不过,Silverlight还提供了另一种方式,即文件拖放功能。用户可以在Windows资源管理器或桌面上选择一个或多个文件,将这些文件拖到Silverlight应用程序上,然后放到某个元素上,应用程序就可以读取这些文件。许多基于Web的上传工具(如SharePoint和微软的SkyDrive服务)经常包含这种功能,以便更轻松地一次性上传整批文件。

2.1 拖放功能在不同系统的表现
  • Windows系统 :拖放功能在Windows计算机上可以无缝工作。
  • Mac系统 :在Mac上,该功能存在问题。Mac的Web浏览器(如Safari)有稍微不同的插件模型,它们不会向托管在网页中的插件提供HTML DOM事件。因此,当在Mac上将文件放到Silverlight内容区域时,网页会接收该事件,但Silverlight应用程序不会。目前,有一个针对Safari浏览器的解决方法,即在托管网页中添加一小段JavaScript代码,手动将拖放事件转发给Silverlight应用程序。具体细节可参考 相关文档 。但在撰写本文时,使用Firefox浏览器的Mac用户即使使用此解决方法也无法将文件拖到Silverlight应用程序中。
2.2 构建支持拖放功能的应用程序

构建支持拖放功能的应用程序步骤如下:
1. 添加接收拖放数据的元素 :通常使用一个大的矩形区域,可使用 Border 或简单的 Rectangle (实际上任何元素都支持拖放功能),并将 AllowDrop 属性设置为 True

<Rectangle x:Name="rectDropSurface" Margin="5" Fill="LightSteelBlue"
 Stroke="SteelBlue" StrokeThickness="1" AllowDrop="True"
</Rectangle>
  1. 处理相关事件 :可以选择响应 DragEnter DragLeave DragOver 事件,以在拖放过程中提供某种状态信息。更重要的是,必须处理 Drop 事件以接收拖放的数据。
<Rectangle x:Name="rectDropSurface" Margin="5" Fill="LightSteelBlue"
 Stroke="SteelBlue" StrokeThickness="1" AllowDrop="True"
 DragEnter="rectDropSurface_DragEnter" DragLeave="rectDropSurface_DragLeave"
 Drop="rectDropSurface_Drop">
</Rectangle>
  1. 事件处理代码示例
Private Sub rectDropSurface_DragEnter(ByVal sender As Object, _
  ByVal e As DragEventArgs)
    lblResults.Text = "You are dragging an object over the drop area."
End Sub

Private Sub rectDropSurface_DragLeave(ByVal sender As Object, _
  ByVal e As DragEventArgs)
    lblResults.Text = ""
End Sub

Private Sub rectDropSurface_Drop(ByVal sender As Object, ByVal e As DragEventArgs)
    ' 检查数据是否存在且格式正确
    If (e.Data IsNot Nothing) AndAlso _
       (e.Data.GetDataPresent(DataFormats.FileDrop)) Then
        Dim files As FileInfo()
        files = CType(e.Data.GetData(DataFormats.FileDrop), FileInfo())

        For Each file As FileInfo In files
            Dim ext As String = System.IO.Path.GetExtension(file.Name)

            ' 检查是否为图片文件
            Select Case ext.ToLower()
                Case ".jpg", ".gif", ".png", ".bmp"
                    Try
                        ' 读取图片,将其包装在BitmapImage中,并添加到列表中
                        Using fs As FileStream = file.OpenRead()
                            Dim source As New BitmapImage()
                            source.SetSource(fs)
                            lstImages.Items.Add(source)
                        End Using
                    Catch err As Exception
                        lblResults.Text = "Error reading file: " & err.Message
                    End Try

                Case Else
                    lblResults.Text = _
                    "The dropped file was not recognized as a supported image type."
            End Select

            lblResults.Text = files.Count().ToString() & _
              " files successfully dropped."
        Next
    End If
End Sub

最后,使用以下模板将 ImageSource 对象转换为图像列表:

<ListBox Grid.Column="1" Margin="5" x:Name="lstImages">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <Image Margin="1"
       Source="{Binding}" Width="95" />
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>
3. 高权限应用程序中的文件访问

高权限应用程序(前提是用户安装了该应用程序或客户端计算机明确配置为信任它)除了具有许多有用的功能外,还会自动获得当前用户的完整文件读写权限。实际上,高权限应用程序不仅可以在用户硬盘的几乎任何位置读写文件,还可以执行许多其他文件系统操作,如创建新目录或遍历目录树进行文件搜索。

3.1 Silverlight与UAC

现代版本的Windows操作系统具有用户账户控制(UAC)功能,它会锁定管理员权限,这会影响文件系统访问的方式。例如,对于名为 c:\AdminLog.doc 的文件,即使当前用户以管理员身份登录,除非Windows执行权限提升(即屏幕变黑并弹出确认对话框,要求用户确认操作),否则该文件无法访问。Silverlight应用程序不会自动执行权限提升,因此Silverlight应用程序永远不会获得管理员权限,也无法访问需要这些权限的文件或目录。不过,也有例外情况,例如用户可以更改当前计算机的UAC设置,或者通过右键单击应用程序快捷方式并选择“以管理员身份运行”来显式启动应用程序。在这种情况下,确认对话框会出现,用户可以接受,Silverlight应用程序将获得访问需要管理员权限的文件系统部分的能力,但这种方法并不被鼓励。

3.2 访问用户文件

在Windows操作系统中,用户特定的文档文件夹是存储各种内容的最有用的位置之一,包括:
- My Documents
- My Music
- My Pictures
- My Videos

可以使用 Environment.GetFolderPath() 方法并传入 Environment.SpecialFolder 枚举中的一个值来获取这些位置的物理路径。示例代码如下:

Dim documentPath As String = _
  Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)

获取“我的”文件夹的路径后,就可以在其中创建、修改和删除文件和目录。执行文件和目录操作最方便的方法是使用 File Directory 类的共享方法,这些方法移植自完整的.NET Framework。以下是一些操作示例:
- 写入文件

Dim documentPath As String = _
  Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim fileName As String = System.IO.Path.Combine(documentPath, "TestFile.txt")

File.WriteAllText(fileName, "This is a test.")
  • 读取文件
Dim documentPath As String = _
  Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim fileName As String = System.IO.Path.Combine(documentPath, "TestFile.txt")

If File.Exists(fileName) Then
    Dim contents As String = File.ReadAllText(fileName)
    lblResults.Text = contents
End If
  • 使用 FileStream StreamWriter 写入文件
Dim documentPath As String = _
  Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim fileName As String = System.IO.Path.Combine(documentPath, "TestFile.txt")

Using fs As New FileStream(fileName, FileMode.Create)
    Dim writer As New StreamWriter(fs)
    writer.Write("This is a test with FileStream.")
    writer.Close()
End Using

无论使用哪种方法,都应该将文件访问代码包装在异常处理块中,以处理潜在的错误。

4. 目录和文件管理

FileStream StreamWriter StreamReader 类允许读写任何文件。结合 File Directory 类,我们可以执行大量的文件管理任务。 Directory 类提供了许多有用的方法,如下表所示:
| 方法 | 描述 |
| — | — |
| CreateDirectory() | 创建一个新目录。如果指定的目录位于另一个不存在的目录中,Silverlight会自动创建所有必需的目录。 |
| Delete() | 删除指定的空目录。若要删除包含内容(子目录和文件)的目录,可添加可选的第二个参数 True 。 |
| EnumerateDirectories | 返回一个 IEnumerable 字符串集合,每个字符串代表指定目录内的一个子目录名。可以使用该方法的重载版本,通过搜索表达式过滤名称。 |
| EnumerateFiles | 返回一个 IEnumerable 字符串集合,每个字符串代表指定目录内的一个文件名。可以使用该方法的重载版本,通过搜索表达式过滤名称。 |
| EnumerateFileSystemEntries | 返回 EnumerateDirectories EnumerateFile 的组合结果,即一个包含所有目录和文件名的 IEnumerable 集合。 |
| Exists() | 返回 True False ,指示指定的目录是否存在,类似于 File.Exists() 方法对文件的检查。 |
| GetCreationTime() GetLastAccessTime() GetLastWriteTime() | 返回一个 DateTime 对象,分别表示目录的创建时间、最后访问时间或最后写入时间。 |
| GetCurrentDirectory() SetCurrentDirectory() | 允许设置或检索当前目录,在需要使用相对路径而不是完整路径时很有用,但通常这些功能不是必需的。 |
| Move() | 接受两个参数:源路径和目标路径。只要目录和其所有内容位于同一驱动器上,就可以将其移动到任何路径。如果需要在不同驱动器之间移动文件,则需要结合复制和删除操作。 |

以下是使用 Directory 类创建文件夹、放置文件并删除文件夹的示例代码:

Dim newDir As String = "c:\TestPath"

Directory.CreateDirectory(newDir)
Dim newFile As String = "testFile.txt"

' 使用System.IO.Path类安全地组合文件路径
Dim filePath As String = System.IO.Path.Combine(newDir, newFile)
File.WriteAllText(filePath, "This is a test file in a new directory!")

MessageBox.Show("When you click OK, the new file and new directory will be deleted.")
Directory.Delete(newDir, True)

Silverlight还包含了 .NET 中的 DirectoryInfo FileInfo 类,它们与 Directory File 类的功能类似,但使用实例方法。如果需要长时间处理特定目录,创建专用的 DirectoryInfo 对象可能更简洁或更高效。示例代码如下:

Dim newDir As New DirectoryInfo("c:\TestPath")
newDir.Create()

Dim filePath As String = System.IO.Path.Combine(newDir.FullName, "testFile.txt")
Dim newFile As New FileInfo(filePath)
Dim writer As StreamWriter = newFile.CreateText()
writer.Write("This is a test file in a new directory!")
writer.Close()

MessageBox.Show("When you click OK, the new file and new directory will be deleted.")
newDir.Delete()
5. 创建目录树

我们可以创建一个简单的文件浏览器,在Silverlight应用程序中浏览本地硬盘。创建这个示例相对容易,前提是运行的是可以使用 FileInfo DirectoryInfo 类的高权限应用程序。

5.1 界面布局

首先,定义界面的标记,使用一个 TreeView (在左侧)和一个 ListBox (在右侧):

<Grid x:Name="LayoutRoot" Background="White" Margin="3">   
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="2*"></ColumnDefinition>
    <ColumnDefinition></ColumnDefinition>
  </Grid.ColumnDefinitions>

  <controls:TreeView x:Name="treeFileSystem" Margin="5">
  </controls:TreeView>         
  <ListBox Margin="0,5,5,5" Grid.Column="1" x:Name="lstFiles"></ListBox>
</Grid>

为了确保良好的性能,该示例只构建展开的树部分。最初,只显示根目录 c:\ 。展开该目录,应用程序会查询第一级子目录。展开其中一个子目录可以看到更多子目录,依此类推。

5.2 核心方法

大部分工作通过自定义方法 AddItem() 完成。 AddItem() 方法需要两个参数:要添加到树中的 DirectoryInfo 对象和要放置该目录的 TreeViewItem 对象集合。以下是添加根目录的代码:

Dim rootDir As New DirectoryInfo("c:\")

' 将根文件夹放在TreeView的第一级
AddItem(rootDir, treeFileSystem.Items)

AddItem() 方法的实现如下:

Private Sub AddItem(ByVal dir As DirectoryInfo, ByVal collection As ItemCollection)
    Dim item As New TreeViewItem()
    item.Tag = dir
    item.Header = dir.Name

    ' 这个占位符字符串永远不会显示,因为节点开始时处于折叠状态
    item.Items.Add("*")
    AddHandler item.Expanded, AddressOf item_Expanded
    AddHandler item.Selected, AddressOf item_Selected

    collection.Add(item)
End Sub

TreeViewItem 展开时,会清除其子项(包括占位符),并检索相应的 DirectoryInfo 对象,然后使用 DirectoryInfo.EnumerateDirectories() 方法获取所有子目录,并通过多次调用 AddItem() 方法将它们添加到树中。代码如下:

Private Sub item_Expanded(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim item As TreeViewItem = CType(sender, TreeViewItem)

    ' 每次展开项时进行刷新
    item.Items.Clear()
    ' 后续代码可根据需求添加,用于获取子目录并添加到树中
End Sub

通过以上步骤,我们可以实现一个在Silverlight应用程序中浏览本地硬盘的文件浏览器,充分展示了Silverlight在浏览器环境下的强大功能。

通过本文的介绍,我们详细了解了Silverlight在文件访问方面的多种功能,包括多文件下载上传、文件拖放、高权限应用程序的文件访问以及目录和文件管理等。这些功能为开发人员提供了丰富的工具,使得在Silverlight应用程序中实现复杂的文件操作变得更加容易。希望本文能对大家在使用Silverlight进行文件处理时有所帮助。

Silverlight文件访问功能全解析(续)

6. 高权限应用下文件操作的综合应用场景

在实际开发中,高权限应用下的文件操作往往不是单一进行的,而是多种操作相互配合以实现特定的功能。下面我们来看一个综合应用场景,假设我们要开发一个文件备份工具,该工具可以将用户指定的文件夹中的所有文件备份到另一个指定的文件夹中。

6.1 功能实现思路
  1. 获取源文件夹和目标文件夹路径 :可以使用 Environment.GetFolderPath() 方法获取用户文档文件夹作为源文件夹示例,同时提示用户输入目标文件夹路径。
  2. 遍历源文件夹中的所有文件和子文件夹 :使用 Directory.EnumerateFileSystemEntries() 方法遍历源文件夹中的所有文件和子文件夹。
  3. 复制文件和文件夹 :对于文件,使用 File.Copy() 方法进行复制;对于文件夹,使用 Directory.CreateDirectory() 方法创建目标文件夹,并递归调用复制方法。
6.2 代码实现
' 获取源文件夹路径
Dim sourcePath As String = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
' 提示用户输入目标文件夹路径
Dim targetPath As String = InputBox("请输入目标文件夹路径", "备份路径", "C:\Backup")

' 调用复制方法
CopyDirectory(sourcePath, targetPath)

Private Sub CopyDirectory(ByVal sourceDir As String, ByVal targetDir As String)
    ' 创建目标文件夹
    If Not Directory.Exists(targetDir) Then
        Directory.CreateDirectory(targetDir)
    End If

    ' 遍历源文件夹中的所有文件和子文件夹
    For Each entry In Directory.EnumerateFileSystemEntries(sourceDir)
        Dim entryName = Path.GetFileName(entry)
        Dim targetEntryPath = Path.Combine(targetDir, entryName)

        If Directory.Exists(entry) Then
            ' 如果是文件夹,递归调用复制方法
            CopyDirectory(entry, targetEntryPath)
        Else
            ' 如果是文件,进行复制
            File.Copy(entry, targetEntryPath, True)
        End If
    Next
End Sub
7. 性能优化与注意事项

在进行文件操作时,性能优化和注意事项是非常重要的,以下是一些建议:

7.1 性能优化
  • 使用 Enumerate 系列方法 :如 Directory.EnumerateDirectories() Directory.EnumerateFiles() ,这些方法在创建集合时不会立即从文件系统中检索对象,而是在迭代集合时才进行检索,这样可以提高性能。
  • 批量操作 :尽量减少单个文件操作的次数,例如批量复制或删除文件。
  • 异步操作 :对于耗时的文件操作,如大文件的上传和下载,使用异步方法(如 UploadFileAsync() )可以避免阻塞主线程,提高用户体验。
7.2 注意事项
  • 权限问题 :在高权限应用中,虽然可以获得更多的文件访问权限,但仍然要注意UAC的影响。避免不必要的管理员权限操作,确保用户明确知晓并同意进行相关操作。
  • 异常处理 :文件操作可能会因为各种原因失败,如文件被占用、磁盘空间不足等。因此,一定要在代码中进行异常处理,确保程序的健壮性。
  • 文件路径安全 :在处理文件路径时,使用 System.IO.Path.Combine() 方法来组合路径,避免手动拼接路径导致的错误。
8. 总结与展望

Silverlight为开发人员提供了丰富的文件访问功能,从基本的文件上传下载到高级的文件拖放和高权限应用下的文件操作,涵盖了多种应用场景。通过合理运用这些功能,我们可以开发出功能强大、用户体验良好的文件处理应用程序。

然而,随着技术的不断发展,Silverlight已经逐渐被其他更现代的技术所取代。但其中的文件操作原理和方法仍然具有一定的参考价值。未来,我们可以期待更加简洁、高效、安全的文件操作技术出现,为开发人员提供更好的开发体验。

流程图总结

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B(多文件下载与上传):::process
    B --> C(文件拖放功能):::process
    C --> D{系统类型}:::decision
    D -->|Windows| E(拖放功能无缝工作):::process
    D -->|Mac| F(存在问题及解决方法):::process
    E --> G(构建支持拖放应用):::process
    F --> G
    G --> H(高权限应用文件访问):::process
    H --> I(Silverlight与UAC):::process
    H --> J(访问用户文件):::process
    J --> K(目录和文件管理):::process
    K --> L(创建目录树):::process
    L --> M(综合应用场景):::process
    M --> N(性能优化与注意事项):::process
    N --> O([结束]):::startend

列表总结

  1. 文件操作功能 :多文件下载上传、文件拖放、高权限应用文件访问、目录和文件管理、创建目录树。
  2. 性能优化方法 :使用 Enumerate 系列方法、批量操作、异步操作。
  3. 注意事项 :权限问题、异常处理、文件路径安全。

通过以上内容,我们对Silverlight的文件访问功能有了全面的了解,希望能帮助开发人员在实际项目中更好地运用这些功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值