1、Read and write simple structured data:
这个示例演示了创建一个内存支持的流,然后通过使用 DataWrite 对象把下面的字符串存储到流中。一旦这个
操作完成了,再使用一个 DataReader 对象把这些字符串从这个流中提取出来。
操作截图:
点击按钮后 ,显示结果:
页面的 xaml:
//将要操作的文本Hello;World;1 2 3 4 5;Très bien!;Goodbye
//输出结果
按钮的操作事件:
//读取文本框中的文本,并使用 DataReader 和 DataWriter 进行读写操作 private async void TransferData(object sender, RoutedEventArgs e) { // 初始化 in-memory stream ,并把数据存储到这个流中 using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { // 创建数据写入器对象支持的内存流 using (var dataWriter = new Windows.Storage.Streams.DataWriter(stream)) { // 获取或设置用于输出流的 Unicode 字符编码。 编码为 UTF-8。 dataWriter.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8; // 在输出流中获取或设置数据的字节顺序。首先存储最低有效字节(最低的地址)。 dataWriter.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; // 转换输入流,并且把它们分割 string[] inputElements = ElementsToWrite.Text.Split(';'); foreach (string inputElement in inputElements) { // 获取字符串的大小。 uint inputElementSize = dataWriter.MeasureString(inputElement); //将 32 位无符号整数值写入输出流。 dataWriter.WriteUInt32(inputElementSize); //将字符串值写入输出流。 dataWriter.WriteString(inputElement); } // 发送 writer 的内容到支持的流。 await dataWriter.StoreAsync(); //对于内存流的实现中,我们调用 flushAsync() 方法是多余的,但是其它类型的流中可能需要这么做 // 为了延长 stream 的生命周期,把这个流从 dataWriter 中分离,所以在 dataWriter 对象调用 Dispose() 方法时, //这个流不会被关闭掉。如果我们分离这个流失败,在调用dataWriter.Dispose() 方法时会优先关闭这个流,阻止了下面DataReader 的调用 dataWriter.DetachStream(); } // 创建这个 input stream 在位置 0,以便这个流可以从开始读 using (var inputStream = stream.GetInputStreamAt(0)) { using (var dataReader = new Windows.Storage.Streams.DataReader(inputStream)) { // 编码和字节顺序需要匹配我们之前的设置使用的 writer // 获取或设置用于输入流的 Unicode 字符编码。 dataReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8; // 在输入流中获取或设置数据的字节顺序。 dataReader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; // 一旦我们把这些内容写成功,然后我们就加载这个流. 从输入流加载数据。 await dataReader.LoadAsync((uint)stream.Size); var receivedStrings = ""; // 继续阅读,直到我们消费掉完整的流。 while (dataReader.UnconsumedBufferLength > 0) { // 注意到当调用 ReadString 方法前需要设置 “code units”的长度。 //这是为什么在写入流时,把每个 string 的长度进行设置 uint bytesToRead = dataReader.ReadUInt32(); receivedStrings += dataReader.ReadString(bytesToRead) + "\n"; } // 把从流中读取的元素输出到 TextBlock 对象中 ElementsRead.Text = receivedStrings; } } }
2、Dump file contents using ReadBytes() :
本示例打开下面图片的顺序访问流,并且使用 ReadBytes() 方法,把它的内容显示为 16 进制数据,
并且存储为 二进制数据。
操作截图:
显示的 16 进制输出:
页面的 xaml :
//用来操作的应用程序包中的图片//显示图片的 16 进制结果
相应按钮的单击事件:
//声明三个变量private const int bytesPerRow = 16;private const int bytesPerSegment = 2;private const uint chunkSize = 4096;//首先打开将要操作的图片,然后把文件放入一个连续访问的流中,然后使用 ReadBytes() 方法从中提取二进制数据。最后,把每个字节转换为 16 进制的数据, //并且格式化后,把这些数据输出到 textblock 中private async void HexDump(object sender, RoutedEventArgs e) { try { //检索并获取图形文件 Uri uri = new Uri("ms-appx:///assets/110Strawberry.png"); var file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri); // 打开一个图像文件的顺序访问流。 using (var inputStream = await file.OpenSequentialReadAsync()) { // 把这个输入流(input stream)传输到 DataReader 对象 using (var dataReader = new Windows.Storage.Streams.DataReader(inputStream)) { uint currChunk = 0; uint numBytes; ReadBytesOutput.Text = ""; // 创建一个字节数组,可以持有足够的字节来填充一排十六进制转储。 var bytes = new byte[bytesPerRow]; do { // 加载下一个块 到 DataReader 的缓冲区 numBytes = await dataReader.LoadAsync(chunkSize);//从输入流加载数据。 // 读出并打印一行 var numBytesRemaining = numBytes; while (numBytesRemaining >= bytesPerRow) { // 使用 DataReader 对象和 ReadBytes() 方法来填补这个字节数组与足够一行的字节 dataReader.ReadBytes(bytes);//从输入流中读取字节值数组。 PrintRow(bytes, (numBytes - numBytesRemaining) + (currChunk * chunkSize)); numBytesRemaining -= bytesPerRow; } // 如果有任何剩余的字节可读,分配一个新的数组,用来装载 DataReader对象中剩余的字节,并且打印到最后一行 // 注意: ReadBytes()填充整个数组,所以如果数组被传入到比在 DataReader 中剩下的缓冲区大 //,将会抛出一个异常。 if (numBytesRemaining > 0) { bytes = new byte[numBytesRemaining]; // 从输入流中读取字节值数组。 dataReader.ReadBytes(bytes); PrintRow(bytes, (numBytes - numBytesRemaining) + (currChunk * chunkSize)); } currChunk++; // If the number of bytes read is anything but the chunk size, then we've just retrieved the last // chunk of data from the stream. Otherwise, keep loading data into the DataReader buffer. //如果读取的字节数决不是块的大小,然后我们检索下一个 //大块的数据流。否则,继续加载数据到 DataReader 缓冲区。 } while (numBytes == chunkSize); } } } catch (Exception ex) { ReadBytesOutput.Text = ex.Message; } }
////// 把从 ReadBytes() 方法中得到的数据,格式化并且输出为一行十六进制数据 /// /// 我们将要操作的数组 /// 值将被格式化为一个地址 private void PrintRow(byte[] bytes, uint currByte) { var rowStr = ""; // Format the address of byte i to have 8 hexadecimal digits and add the address // of the current byte to the output string. rowStr += currByte.ToString("x8"); // 格式化输出 for (int i = 0; i < bytes.Length; i++) { //如果完成了一段,添加一个 空格。 if (i % bytesPerSegment == 0) { rowStr += " "; } // 把当前字节值转换成十六进制,并将它添加到输出字符串。 rowStr += bytes[i].ToString("x2"); } // 把当前行追加到 TextBlock 中 ReadBytesOutput.Text += rowStr + "\n"; }