文件与数据

本文详细介绍了UWP中文件与目录的操作,包括StorageFile、StorageFolder、KnownFolders等重要类型,以及读写本地文件的方法。此外,还讲解了FileIO、PathIO、DataWriter和DataReader的使用,以及应用设置、访问可移动存储、StorageApplicationPermissions、XML与JSON数据处理和数据共享的功能。通过示例代码展示了如何实现文件操作、应用设置的读写、数据共享以及App Service的调用。
摘要由CSDN通过智能技术生成

1. 文件与目录

(1) 文件/目录操作的相关类型

与文件/目录操作有关的类型主要分布在Windows.Storage命名空间及该命名空间下的子命名空间中。下面列出了与文件/目录操作有关的几个重要类型。

  • StorageFile 表示一个文件类型,通过该类,可以对某个文件进行一些常用操作,例如重命名、删除、获取基本属性等
  • StorageFolder 表示一个目录实例,可以对某个目录进行重命名、复制、删除等操作
  • KnownFolders 一个静态类型,公开一系列静态属性,通过这些属性可以直接获取特殊目录的引用,如图片库、音乐库、视频库等
  • FileIO 公开一系列静态方法,以方便对文件进行读写操作,简化了对文件进行操作的步骤,该类针对StorageFile类实例而设计
  • PathIO 同上,公开一系列便捷的方法来读写文件,与FileIO不同的是,PathIO是面向路径的,即在读写文件时不需要创建StorageFile实例,只需要通过字符串指定文件的路径就可以了

(2) 读写本地文件

当应用程序安装完成后,操作系统会为每个应用分配独立的文件夹,每个应用程序只能访问自己的文件夹。这个文件夹也叫本地目录,可以通过ApplicationData类的LocalFolder属性获得与本地目录相关的StorageFolder实例,随后应用程序就可以使用该StorageFolder对象来读写文件了。
下面示例将演示如何读写本地文件。示例首先将一个随机生成的字节序列写入本地文件,然后再从已保存的文件中读出这些字节序列。

  1. MainPage页面的布局如下XAML所示:
        <StackPanel Spacing="10">
            <TextBlock Text="写入文件" FontSize="36"/>
            <Button x:Name="writeBtn" Content="将字节序列写入文件" Tapped="writeBtn_Tapped"/>
            <TextBlock x:Name="tbBytes" TextWrapping="Wrap" FontSize="24"/>
            <Line X1="0" Y1="0" X2="100" Y2="0" StrokeThickness="6" Stretch="Fill" Stroke="LightGray"/>
            <TextBlock Text="从文件读入" FontSize="36"/>
            <Button x:Name="readBt" Content="读取字节序列" Tapped="readBt_Tapped"/>
            <TextBlock x:Name="tbReadBytes" FontSize="24" TextWrapping="Wrap"/>
        </StackPanel>
  1. 分别处理两个Button控件的Tapped事件。
        private async void writeBtn_Tapped(object sender, TappedRoutedEventArgs e)
        {
   
            writeBtn.IsEnabled = false;
            //产生字节数组
            Random rand = new Random();
            byte[] data = new byte[8];
            rand.NextBytes(data);
            //从字节数组产生缓冲区对象
            IBuffer buffer = data.AsBuffer();
            //在本例目录中创建新文件
            StorageFile newFile = await local.CreateFileAsync("my.data", CreationCollisionOption.ReplaceExisting);
            //打开文件流
            using (IRandomAccessStream outputStream = await newFile.OpenAsync(FileAccessMode.ReadWrite))
            {
   
                //将缓冲区的内容写入流
                await outputStream.WriteAsync(buffer);
            }
            //显示已写入的字节序列
            tbBytes.Text = $"已向文件写入:{BitConverter.ToString(data)}";
            writeBtn.IsEnabled = true;
        }

        private async void readBt_Tapped(object sender, TappedRoutedEventArgs e)
        {
   
            readBt.IsEnabled = false;
            //获取文件
            var file = await local.GetFileAsync("my.data");
            if (file != null)
            {
   
                //用于存放读到的数据的缓冲区
                IBuffer buffer = null;
                //打开流
                using (var inputStream = await file.OpenReadAsync())
                {
   
                    //实例化缓冲区对象
                    buffer = WindowsRuntimeBuffer.Create((int)inputStream.Size);
                    //从流中读入数据,存放到缓冲区中
                    await inputStream.ReadAsync(buffer,buffer.Capacity,InputStreamOptions.None);
                }
                //显示读到的字节序列
                tbReadBytes.Text = $"读到的字节序列:{BitConverter.ToString(buffer.ToArray())}";
            }
            readBt.IsEnabled = true;
        }

在Running App中读写数据通常用到缓冲区对象,即IBuffer接口及实现了该接口的Buffer类。在声明变量时,一般使用IBuffer来作为类型标识。

            IBuffer buffer = data.AsBuffer();

有过.NET开发经历的开发者会明白,在托管代码中处理字节序列时,用得最多的是通过字节数组(byte[])作为临时缓冲区,而由于UWP中要用到IBuffer缓冲区对象,这就涉及到两种类型之间的转换。为了实现它们之间的互相转化,API库为它们定义了相关的扩展方法:

  • 调用byte[]实例的AsBuffer方法,可以返回IBuffer实例。
  • 调用IBuffer实例的ToArray方法,可以得到byte数组。

StorageFile类有两种方法打开文件流:OpenReadAsync方法打开的流只能用于读取,不能进行写操作,在读取文件时使用该方法较合适;OpenAsync方法既可以打开只读的流,也可以打开可读可写的流,这决定于传递给方法参数的FileAccessMode枚举的值。

(3) FileIO与PathIO

FileIO类与PathIO都公开了一系列方法,以便简捷地读写文件。如下所示,可以将这些方法按照读写的方向分为两组。
写入:

  • AppendLinesAsync 在文件原有内容的基础上追加一行或多行文本,每次写入的文本的结尾自动加上换行符。

  • AppendTextAsync 向文件的现有内容追加文本。

  • WriteBufferAsync 将缓冲区中的数据写入文件。

  • WriteBytesAsync 将字节数组写入文件。

  • WriteTextAsync 向文件写入文本,每次写入的内容会替换文件的现有内容。

  • WriteLinesAsync 向文件写入一行或多行文本,写入的文本末尾会自动加上换行符,文件的现有内容会被替换。
    读取:

  • ReadTextAsync 获取文件中所有文本内容。

  • ReadLinesAsync 从文件中读取一行或多行文本。

  • ReadBufferAsync 将从文件读取的数据存入到缓冲区对象中。

接下来用一个示例来演示FileIO和PathIO两个类的使用方法。
页面的布局XAML如下:

        <StackPanel Spacing="10">
            <TextBox x:Name="txtInput" Header="请输入内容:" TextWrapping="Wrap"/>
            <Button Tag="write" Content="写入文件" Tapped="Button_Tapped"/>
            <Button Tag="read" Content="读取文件" Tapped="Button_Tapped"/>
            <TextBox x:Name="txtOutput" IsReadOnly="True" Header="读出的内容:" TextWrapping="Wrap"/>
        </StackPanel>

在本示例中,将使用FileIO类将文本写进本地文件中,随后使用PathIO类从本地文件中读出文本内容。Button控件的Tapped事件处理程序如下:

        private async void Button_Tapped(object sender, TappedRoutedEventArgs e)
        {
   
            Button btn = sender as Button;
            btn.IsEnabled = false;
            if ((sender as Button).Tag.ToString() is "write")
            {
   
                if (txtInput.Text.Length < 1)
                {
   
                    return;
                }
                //获取本地目录的引用
                var local = ApplicationData.Current.LocalFolder;
                //创建新文件
                var newFile = await local.CreateFileAsync("data.txt",CreationCollisionOption.ReplaceExisting);
                //写入文件
                await FileIO.WriteTextAsync(newFile,txtInput.Text);
            }
            else
            {
   
                try
                {
   
                    //直接读取文件内容
                    txtOutput.Text = await PathIO.ReadTextAsync("ms-appdata:///local/data.txt");
                }
                catch (Exception ex)
                {
   
                    txtOutput.Text = ex.Message;
                }
            }
            btn.IsEnabled = true;
        }

从上面代码中可以看出,使用FileIO类和PathIO类来读写文件非常简便。要注意的是,在使用PathIO类读取文件时使用的是文件路径,本地文件夹的路径为:

ms-appdata:///local/

示例中的data.txt文件是放在本地目录下的,因此文件的路径为:

ms-appdata:///local/data.txt

还要注意:PahtIO类只能对已经存在的文件进行操作,如果文件不存在,则会发生异常。

(4) DataWriter与DataReader

这两个类都是以流对象作为载体而进行的读写操作。通过这两个类的封装,使流操作变得更加方便,功能上类似于FileIO类和PathIO类。但是,FileIO类和PathIO类所操作的目标是文件,而DataWriter类和DataReader类是面向流的,既可以用来读写文件,也可以用于读写内存数据,在网络通信中还可以读写网络数据。可见,DataWriter与DataReader适用的范围更广。
在写入数据时,可以使用DataWriter类公开的如WriteByte、WriteDateTime、WriteInt32、WriteString等方法;同理,在读取数据时,可以调用DataReader类的ReadByte、ReadDateTine、ReadString等方法。这些方法的优点在于封装了基础数据类型的处理,可以很方便地进行读写。不过要注意的是,读出数据的顺序应当与数据写入时的顺序相同。例如先写入一个byte类型的值,后写入一个int类型的值,在读出数据的时候,应该先读出byte类型的值,在读出int类型的值。
下面示例先用DataWriter类向本地文件写入数据,然后使用DataReader类将数据读出来。应用程序主页面的XAML代码如下:

        <StackPanel Spacing="10">
            <RichTextBlock FontSize="20" TextWrapping="Wrap">
                <Paragraph>
                    写入的内容及顺序如下:
                </Paragraph>
                <Paragraph>
                    <Span>1、bool值:true</Span>
                    <LineBreak/>
                    <Span>2、DateTime类型值:2020-12-20</Span>
                    <LineBreak/>
                    <Span>3、字符串:测试文本</Span>
                </Paragraph>
            </RichTextBlock>
            <Button Tag="write" Content="写入文件" Tapped="Button_Tapped"/>
            <Line X1="0" X2="20" Stretch="Fill" StrokeThickness="5" Stroke="LightYellow"/>
            <Button Tag="read" Content="读取内容" Tapped="Button_Tapped"/>
            <TextBlock x:Name="tbResult" FontSize="20" TextWrapping="Wrap"/>
        </StackPanel>

示例要向本地文件写入三段数据:第一段为bool类型的值ture;第二段数据为当前日期值;第三段数据是字符串"测试文本"。
Button控件的事件处理程序如下:

        private async void Button_Tapped(object sender, TappedRoutedEventArgs e)
        {
   
            if ((sender as Button).Tag.ToString() is "write")
            {
   
                //创建新文件
                var file = await localFolder.CreateFileAsync("demo.dat",CreationCollisionOption.ReplaceExisting);
                //打开文件流
                using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
                {
   
                    //实例化DataWriter
                    DataWriter dw = new DataWriter(outputStream);
                    //设置默认编码格式
                    dw.UnicodeEncoding = UnicodeEncoding.Utf8;
                    //写入bool值
                    dw.WriteBoolean(true);
                    //写入日期时间值
                    DateTime dt = DateTime.Now;
                    dw.WriteDateTime(dt);
                    //写入字符串
                    string str = "测试文本";
                    //计算字符串的长度
                    uint len = dw.MeasureString(str);
                    //先写入字符串的长度
                    dw.WriteInt32((int)len);
                    //再写入字符串
                    dw.WriteString(str);
                    //以下方式必须调用
                    await dw.StoreAsync();
                    //解除DataWriter与流的关联
                    //dw.DetachStream();
                    dw.Dispose();
                }
                await new MessageDialog
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值