Stream 读取Windows Phone 8 SD卡上的文件时出现问题

Stream 读取Windows Phone 8 SD卡上的文件时出现问题,stream,windows-phone-8,sd-card,seek,Stream,Windows Phone 8,Sd Card,Seek,我无法读取Windows Phone SD卡上的文件。我使用ExternalStorageFile.OpenForReadAsync获取有效的流对象。但是,尽管stream CanSeek属性为true,但忽略任何查找操作,并且不移动位置 private async void ReadFileOnSDCard(ExternalStorageFile file) { Stream stream = await file.OpenForReadAsync();

我无法读取Windows Phone SD卡上的文件。我使用ExternalStorageFile.OpenForReadAsync获取有效的流对象。但是,尽管stream CanSeek属性为true,但忽略任何查找操作,并且不移动位置

    private async void ReadFileOnSDCard(ExternalStorageFile file)
    {
        Stream stream = await file.OpenForReadAsync();
          using (stream)
          {
                 long curPos= stream.Seek(100, SeekOrigin.Begin);
                 long pos = stream.Position;

//curPos和pos都是0。

我猜您正在读取一个扩展名为0的文件。 不幸的是,您无法从Windows Phone上的SD卡读取它们。 如果您正在读取的文件属于这些保留扩展名,Windows Phone只需忽略它们即可

假设您没有阅读这些保留的扩展,您可以按照以下两个步骤来解决问题

1/首先检查是否已添加
到您的WMAppManifest.xml

2/如果没有,请注册文件关联扩展名,例如.gpx

<FileTypeAssociation TaskID="_default" Name="GPX" NavUriFragment="fileToken=%s">
  <Logos>
    <Logo Size="small" IsRelative="true">Assets/Route_Mapper_Logo33x33.png</Logo>
    <Logo Size="medium" IsRelative="true">Assets/Route_Mapper_Logo69x69.png</Logo>
    <Logo Size="large" IsRelative="true">Assets/Route_Mapper_Logo176x176.png</Logo>
  </Logos>
  <SupportedFileTypes>
    <FileType ContentType="application/gpx">.gpx</FileType>
  </SupportedFileTypes>
</FileTypeAssociation>

资源/路线\u映射器\u Logo33x33.png
资源/路线\u映射器\u Logo69x69.png
资源/路线\u映射器\u Logo176x176.png
.gpx

我也在为同样的问题而斗争。Seek确实在Microsoft.Phone.Storage.NativeFileStream中被破坏,这是SD卡上文件的流类型。最后,我用ILspy查看了这个类,如下所示:

public override long Seek(long offset, System.IO.SeekOrigin origin)
{
   ...
   uint num = (uint)((ulong)(offset & -4294967296L) >> 32);
   uint num2 = (uint)(offset & (long)((ulong)-1));
   uint num3 = NativeFileStream.SetFilePointer(this.m_handle, num, ref num2, 
   ...
}
和函数SetFilePointer:


要使寻道工作,偏移量值应该在长的32位以上。

如果文件很小,则可以简单地将流复制到MemoryStream。我已经对此进行了测试,并且效果良好:

Stream s = await file.OpenForReadAsync();
MemoryStream ms = new MemoryStream();
s.CopyTo(ms);
但是,如果文件太大,您将遇到内存问题,因此可以使用以下流包装器类来纠正Microsoft的错误(尽管在Windows Phone的未来版本中,一旦错误得到修复,您需要禁用此修复):

使用系统;
使用System.IO;
命名空间WindowsPhoneBugFix
{
/// 
///流包装器,用于绕过ExternalStorageFile.OpenForReadAsync()返回的流的错误流读取
/// 
公共密封类ExternalStorageFileWrapper:流
{
私有流_Stream;//底层流
公共ExternalStorageFileWrapper(流)
{
if(流==null)
抛出新的ArgumentNullException(“流”);
_溪流=溪流;
}
//此处描述的解决方法-http://stackoverflow.com/a/21538189/250254
公共覆盖长寻道(长偏移,参见原始坐标系)
{
ulong uoffset=(ulong)偏移量;
ulong fix=((uoffset&0xffffffffffl)>32);
返回_stream.Seek((长)固定,原点);
}
公共覆盖布尔可读取
{
获取{return\u stream.CanRead;}
}
公共覆盖布尔搜索
{
获取{return\u stream.CanSeek;}
}
公共覆盖布尔可写
{
获取{return\u stream.CanWrite;}
}
公共覆盖无效刷新()
{
_stream.Flush();
}
公共覆盖长长度
{
获取{return\u stream.Length;}
}
公众优先多头仓位
{
得到
{
返回流位置;
}
设置
{
_流。位置=值;
}
}
公共重写整型读取(字节[]缓冲区、整型偏移量、整型计数)
{
返回_stream.Read(缓冲区、偏移量、计数);
}
公共覆盖无效设置长度(长值)
{
_stream.SetLength(值);
}
公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数)
{
_写入(缓冲区、偏移量、计数);
}
}
}
此处有代码可用于访问您的项目:

我想我自己也遇到了同样的问题。那么,您是否只是简单地用垃圾/0填充文件,以便可以在文件的更深处开始偏移量?比我习惯的级别低一点,所以如果我的措辞有点粗糙,我很抱歉。我想知道是否可以从Microsoft.Phone.Storage.NativeFileStream继承并覆盖Seek方法?NativeFileStream的实例是在SD卡上打开文件时得到的,所以我认为覆盖不是一个解决方案。我有一个简单的带有重写Seek的流包装器类,在调用底层流的Seek方法之前,我只需将传递的偏移量值移到更高的32位,这对我来说也是有效的。我的答案贴在下面。但为了方便起见,这里有一个指向代码的链接-可能是
using System;
using System.IO;

namespace WindowsPhoneBugFix
{
    /// <summary>
    /// Stream wrapper to circumnavigate buggy Stream reading of stream returned by ExternalStorageFile.OpenForReadAsync()
    /// </summary>
    public sealed class ExternalStorageFileWrapper : Stream
    {
        private Stream _stream; // Underlying stream

        public ExternalStorageFileWrapper(Stream stream)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            _stream = stream;
        }

        // Workaround described here - http://stackoverflow.com/a/21538189/250254
        public override long Seek(long offset, SeekOrigin origin)
        {
            ulong uoffset = (ulong)offset;
            ulong fix = ((uoffset & 0xffffffffL) << 32) | ((uoffset & 0xffffffff00000000L) >> 32);
            return _stream.Seek((long)fix, origin);
        }

        public override bool CanRead
        {
            get { return _stream.CanRead; }
        }

        public override bool CanSeek
        {
            get { return _stream.CanSeek; }
        }

        public override bool CanWrite
        {
            get { return _stream.CanWrite; }
        }

        public override void Flush()
        {
            _stream.Flush();
        }

        public override long Length
        {
            get { return _stream.Length; }
        }

        public override long Position
        {
            get
            {
                return _stream.Position;
            }
            set
            {
                _stream.Position = value;
            }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            return _stream.Read(buffer, offset, count);
        }

        public override void SetLength(long value)
        {
            _stream.SetLength(value);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            _stream.Write(buffer, offset, count);
        }
    }
}