文件的读写对我们来说不应该陌生,而应该说是非常熟悉了。在学习.NET其他开发技术的时候,IO是我们必须学习的,毕竟那是数据存储与处理的最基本操作。
在Windows Store应用程序开发中,同样需要对文件的读写,但由于安全与权限的限制,我们不可能像以前那样“自由干活”了。这是有好处的,我们要知道,“板砖”应用是针对移动平台的,至少通常情况下是这样的。如果我们希望像过去一样可以自由地读写各种路径,那不妨考虑使用传统桌面应用。
其实,什么叫Windows 8应用程序开发,并不仅仅包含Store应用,只要能在Win 8上运行的程序我们都可以说是Windows 8应用,像老套一点的MFC,以前的Windows Form,以及后来的WPF等等都可以并入Windows 8应用。
在商店应用程序中,通常我们要读写的目录有两类,一类是应用程序数据文件夹,另一类是用户的文档库,至于路径,如果你认为ms-appx://和ms-appdata://不好记的话,你可以干脆不记,就算你不知道这种路径表示法也不会影响你写程序的,至于你信不信,反正我深信不疑。
现在,我们拿出文本第一个例子,看看如何利用现有API来访问应用程序的本地数据目录。
第一步,新建一个“板砖”应用项目,这个不用我说了,此处省略38个字。
第二步,布局,MainPage.xaml的XAML如下:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<RichTextBlock Margin="15">
<Paragraph FontSize="24">
<Span>本地存储目录:</Span>
<Run x:Name="rnLocal"/>
<LineBreak/>
<LineBreak/>
<Span>漫游存储目录:</Span>
<Run x:Name="rnRoaming"/>
<LineBreak/>
<LineBreak/>
<Span>临时目录:</Span>
<Run x:Name="rnTemp"/>
</Paragraph>
</RichTextBlock>
</Grid>
</Page>
第三步,编写C#代码,尽管外面谣言四起,但我还是很喜欢C#,毕竟谣言起于愚者,止于智者。
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.rnLocal.Text = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
this.rnRoaming.Text = Windows.Storage.ApplicationData.Current.RoamingFolder.Path;
this.rnTemp.Text = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path;
}
其实从上面代码中你已经看出,为什么我前面说即使你不记住路径的架构方法也可以轻松访问这些文件夹的原因了。
还是运行一下吧。
从运行结果中我们看到了,这些目录都位于【用户】\\【AppData\\Local】\\【应用程序包名】下面。
接下来拿出本文第二个例子,向本地数据存储区中读写文件。
这玩意儿就相当灵活了,最简单的方法,有两个类可以实现:FileIO和PathIO。
都是静态类,直接调用方法就完事了,这里选择FileIO类来做实验。
第一步,新建一个商店应用项目。
第二步,主页面的XAML如下:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox x:Name="txtInput" Margin="13" Grid.Row="0" TextWrapping="Wrap"/>
<StackPanel Orientation="Horizontal" Margin="14,10" Grid.Row="1">
<Button FontFamily="Segoe UI Symbol" FontSize="25" Click="onWrite" >
<Button.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tbSob" Grid.Column="0" Text=""/>
<TextBlock Grid.Column="1" Text="写入文件"/>
</Grid>
</Button.Content>
</Button>
<Button Margin="16,0,0,0" FontFamily="Segoe UI Symbol" FontSize="25" Click="onRead" >
<Button.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="从文件读取"/>
<TextBlock Grid.Column="1" Text="{Binding ElementName=tbSob,Path=Text}" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<RotateTransform Angle="180"/>
</TextBlock.RenderTransform>
</TextBlock>
</Grid>
</Button.Content>
</Button>
</StackPanel>
<TextBlock x:Name="txtRead" Grid.Row="2" Margin="15" TextWrapping="Wrap" FontSize="24"/>
</Grid>
第三步,编写代码。
private async void onWrite(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(this.txtInput.Text)) return;
var local = Windows.Storage.ApplicationData.Current.LocalFolder;
var myFile = await local.CreateFileAsync("my.txt");
if (myFile != null)
{
await Windows.Storage.FileIO.WriteTextAsync(myFile, this.txtInput.Text);
Windows.UI.Popups.MessageDialog dlg = new Windows.UI.Popups.MessageDialog("写入成功。");
await dlg.ShowAsync();
}
}
private async void onRead(object sender, RoutedEventArgs e)
{
Windows.UI.Popups.MessageDialog dlg = null;
string msg = string.Empty;
try
{
var local = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await local.GetFileAsync("my.txt");
if (file != null)
{
this.txtRead.Text = await Windows.Storage.FileIO.ReadTextAsync(file);
msg = "读取完成。";
}
}
catch (Exception ex)
{
msg = ex.Message;
}
dlg = new Windows.UI.Popups.MessageDialog(msg);
await dlg.ShowAsync();
}
运行的结果如下图所示。
下面我们亮出第二把剑——KnownFolders类,使用它的静态成员,我们可以获取如“我的图片”、“我的音乐”、“我的文档”等用户个人目录的路径,这样我们也可以在其中进行文件的读写。就是包含下图中显示的这几个家伙。
不用一个个解释了吧,以小学五年级的英语水平也能理解是啥意思了。
下面拿出本文第三个例子,把文件写到文档库中。
第一步,新建商店应用程序。
第二步,主页布局比较简陋,没办法,生活艰难。
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Margin="20">
<TextBox x:Name="txtInput" TextWrapping="Wrap" Height="320" FontSize="20"/>
<Button Content="保存到文档库" Margin="8,10,0,0" Padding="12,7" FontSize="25" Click="onSaveDoc"/>
</StackPanel>
</Grid>
第三步,编写后台代码,把文本框中的内容写到文档库中。
private async void onSaveDoc(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(this.txtInput.Text)) return;
var MyDocuments = Windows.Storage.KnownFolders.DocumentsLibrary;
// 创建文件
var tmdFile = await MyDocuments.CreateFileAsync("Data.tmd");
if (tmdFile != null)
{
string strInfo = string.Empty;
try
{
await Windows.Storage.FileIO.WriteTextAsync(tmdFile, this.txtInput.Text);
strInfo = "已写入文档。";
}
catch (Exception ex)
{
strInfo = ex.Message;
}
// 提示操作结果
Windows.UI.Popups.MessageDialog dlg = new Windows.UI.Popups.MessageDialog(strInfo);
await dlg.ShowAsync();
}
}
第四步,还没完,用户个人文档不像前面的写入应用程序数据存储区那么轻松,这里毕竟要考虑安全问题,因此,打开清单文件设计器,切换到“功能”选项卡,勾选“文档库”。
这时候我们看到标签上显示了一个红叉,因为出于安全因素,虽然选用了可访问文档库,但并不意味着你在里面可以为所欲为,必须指定文件类型,而你的代码只能操作指定的文件类型,不能操作其他未指定的文件。
切换到“声明”选项卡,从下拉列表中选择“文件类型关联”,点击“添加”按钮,然后在窗格的右边进行,我们的文件类是 tmd文件。
现在,你可以尝试运行程序了。
操作成功后,打开“我的文档”,找到Data.tmd文件,用记事本打开它,看看里面是否有内容。
如果看到已保存的内容,说明实验成功。
例子代码稍后会上传到【资源】中。