【WP8】线程安全的StorageHelper

14-08-29 12:32更新:修复StorageHelper部分bug

 

WP8以后提供了StorageFile的方式访问文件,StorageFile对文件的操作只提供了异步的支持,包括WP8.1 RT也没有对同步读写文件的支持,可以看出异步在移动开发中的重要性,而且Win8也是通过StorageFile进行文件操作的

跟WP7上的IsolatedStorageFile相比,StorageFile使用起来并不方便,最近总结了一些资料,写了一个通用的类库

StorageFile默认是线程不安全的,如果多个线程同时对文件进行读写会抛出异常,例如多图的场景比较常见

让StorageFile使用起来更加方便,同时提供了线程安全的异步操作,同时也对IsolatedStorageFile(Silverlight)进行了封装

一、StorageFile要点:

  StorageFile

    1、访问文件(两种方式)

    //访问安装目录下的test.txt文件,如果不存在,会抛出FileNotFoundException异常

    //1、访问当前目录下的文件
    var folder = Package.Current.InstalledLocation;
    var storageFile = await folder.GetFileAsync("test.txt");

    //2、通过Uri访问文件,Uri为绝对路径
    storageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appdata:///local/test.txt", UriKind.Absolute));

    //安装文件目录Uri前缀:ms-appx:///
    //本地目录Uri前缀:ms-appdata:///local/

  

    2、没有提供判断文件是否存在的函数,这里通过异常来判断文件是否存在:

    try
    {
        await StorageFile.GetFileFromApplicationUriAsync(new Uri(string.Format("ms-appdata:///local/{0}", filePath), UriKind.Absolute));
        return true;
    }
    catch (Exception)
    {
        return false;
    }

  测试发现:使用上面的形式访问文件会出现问题(比如文件明明存在,却还是会报FileNotFound异常),故StorageHelper不适用上面的形式,而是用通过文件夹访问的形式访问文件,可以解决该问题,目前尚不清楚原因

    //发现通过ms-appdata:///local/访问的方会出现问题,现改成通过下面方式访问文件
    filePath = filePath.Trim('/').Replace("/", "\\");
    var file = await ApplicationData.Current.LocalFolder.GetFileAsync(filePath);

  

    3、创建文件

    //如果文件已经存在,会抛出异常
    var storageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName);
    using (var stream = await storageFile.OpenStreamForWriteAsync())
    {
        stream.Write(data, 0, data.Length);
    }

  StorageFolder 

    //创建文件夹(用\\分开,前后都不加\\)
    var folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("aa\\bb\\cc\\dd");
        
    //访问文件夹
    var folder = await ApplicationData.Current.LocalFolder.GetFolderAsync("aa\\bb\\cc\\dd");

二、线程安全

  IsolatedStorageFile的同步操作这里使用线程锁来实现线程安全

    //线程锁
    private static readonly object lockObj = new object();

    public Stream ReadFile(string filePath)
    {
        lock (lockObj)
        {
            using (var storageFile = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!storageFile.FileExists(filePath))
                {
                    throw new FileNotFoundException(string.Format("没有找到文件:{0}", filePath));
                }

                using (var fs = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, storageFile))
                {
                    var stream = new MemoryStream();
                    fs.CopyTo(stream);

                    stream.Seek(0, SeekOrigin.Begin);
                    return stream;
                }
            }
        }
    }

  异步线程锁使用 Asynclock,可以在Nuget下载到(Enough.AsyncLock

  Asynclock提供了两个类:AsyncSemaphore,AsyncLock

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Enough.Async
{
    public class AsyncSemaphore
    {
        private readonly static Task _completed = Task.FromResult(true);
        private readonly Queue<TaskCompletionSource<bool>> _waiters = new Queue<TaskCompletionSource<bool>>();
        private int _currentCount;

        public AsyncSemaphore(int initialCount)
        {
            if (initialCount < 0)
            {
                throw new ArgumentOutOfRangeException("initialCount");
            }
            _currentCount = initialCount;
        }

        public Task WaitAsync()
        {
            lock (_waiters)
            {
                if (_currentCount > 0)
                {
                    _currentCount--;
                    return _completed;
                }
                else
                {
                    var waiter = new TaskCompletionSource<bool>();
                    _waiters.Enqueue(waiter);
                    return waiter.Task;
                }
            }
        }

        public void Release()
        {
            TaskCompletionSource<bool> toRelease = null;
            lock (_waiters)
            {
                if (_waiters.Count > 0)
                {
                    toRelease = _waiters.Dequeue();
                }
                else
                {
                    _currentCount++;
                }
            }
            if (toRelease != null)
            {
                toRelease.SetResult(true);
            }
        }
    }
}
AsyncSemaphore
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Enough.Async
{
    /// <summary>AsyncLock locks across one or several await calls.
    /// 
    /// </summary>
    public class AsyncLock
    {
        private readonly AsyncSemaphore _semaphore;
        private readonly Task<Releaser> _releaser;

        public AsyncLock()
        {
            _semaphore = new AsyncSemaphore(1);
            _releaser = Task.FromResult(new Releaser(this));
        }

        public Task<Releaser> LockAsync()
        {
            var wait = _semaphore.WaitAsync();
            return wait.IsCompleted ?
                _releaser :
                wait.ContinueWith((_, state) => new Releaser((AsyncLock)state),
                    this, CancellationToken.None,
                    TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
        }


        public struct Releaser : IDisposable
        {
            private readonly AsyncLock _toRelease;

            internal Releaser(AsyncLock toRelease) 
            { 
                _toRelease = toRelease; 
            }

            public void Dispose()
            {
                if (_toRelease != null)
                {
                    _toRelease._semaphore.Release();
                }
            }
        }
    }
}
AsyncLock

三、接口与实现

  提供线程安全的异步操作(IsolatedStorageFile和StorageFile)

  IStorageHelper:提供基本的文件操作相关方法

  约定:
     1、文件夹用'/'分割,
     2、路径不以斜杠'/'开头
     3、文件夹路径以'/'结束
// *************************************************
// 
// 作者:bomo
// 小组:WP开发组
// 创建日期:2014/8/28 21:49:04
// 版本号:V1.00
// 说明: 文件操作接口类,提供文件操作的相关方法
// 
// *************************************************
// 
// 修改历史: 
// Date                WhoChanges        Made 
// 08/28/2014         bomo         Initial creation 
//
// *************************************************
// 约定:
//   1、文件夹用'/'分割,
//   2、路径不以斜杠'/'开头
//   3、文件夹路劲以'/'结束


using System.IO;
using System.Threading.Tasks;

namespace TestDemo
{
    public interface IStorageHelper
    {
        #region 同步方法

        Stream ReadFile(string filePath);

        string ReadText(string filePath);

        void WriteFile(Stream stream, string filePath, bool replace = false);

        void WriteFile(byte[] data, string filePath, bool replace = false);

        void WriteText(string text, string filePath, bool replace = false);

        bool FileExists(string filePath);

        bool DirectoryExists(string directory);

        bool DeleteFile(string filePath);

        bool DeleteDirectory(string directory, bool isDeleteAll = false);

        bool CreateDirectory(string directory);

        long GetFileLength(string filePath);

        string[] GetFiles(string directory);

        string[] GetDirectories(string directory);

        /// <summary>
        /// 序列号类到文件(Xml)
        /// </summary>
        void Serialize<T>(string filePath, T obj);

        T DeSerialize<T>(string filePath);

        void CopyPackageFileToLocal(string source, string target = null, bool replace = false);

        void CopyPackageFolderToLocal(string source, string target = null, bool replace = false);

        Stream GetResourceStream(string filePath);

        #endregion

        #region 异步方法

        Task<Stream> ReadFileAsync(string filePath);

        Task<string> ReadTextAsync(string filePath);

        Task WriteFileAsync(Stream stream, string filePath, bool replace = false);

        Task WriteFileAsync(byte[] data, string filePath, bool replace = false);

        Task WriteTextAsync(string text, string filePath, bool replace = false);

        Task<bool> FileExistsAsync(string filePath);

        Task<bool> DirectoryExistsAsync(string directory);

        Task<bool> DeleteFileAsync(string filePath);

        Task<bool> DeleteDirectoryAsync(string directory, bool isDeleteAll = false);

        Task<bool> CreateDirectoryAsync(string directory);

        Task<ulong> GetFileLengthAsync(string filePath);

        Task<string[]> GetFilesAsync(string directory);

        Task<string[]> GetDirectoriesAsync(string directory);

        Task SerializeAsync<T>(string filePath, T obj);

        Task<T> DeSerializeAsync<T>(string filePath);

        /// <summary>
        /// 拷贝安装目录的文件到本地
        /// </summary>
        Task CopyPackageFileToLocalAsync(string source, string target = null, bool replace = false);

        /// <summary>
        /// 拷贝安装目录的文件夹(包括子文件夹和子文件)到本地
        /// </summary>
        Task CopyPackageFolderToLocalAsync(string source, string target = null, bool replace = false);

        Task<Stream> GetResourceStreamAsync(string filePath);
        
        #endregion
    }
}

  IsolatedStorageFile不支持从安装目录拷贝文件夹,StorageFile不支持同步处理文件

辅助扩展类

using System;
using System.IO;
using System.Threading.Tasks;

namespace TestDemo
{
    public static class StreamReaderExtension
    {
        public static async Task<String> ReadToEndAsyncThread(this StreamReader reader)
        {
            return await Task.Factory.StartNew<String>(reader.ReadToEnd);
        }
    }
}
StreamReaderExtension

 

using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Xml.Serialization;
using Enough.Async;

namespace TestDemo
{
    public class IsolatedStorageHelper : IStorageHelper
    {
        private static readonly Enough.Async.AsyncLock asyncLock = new Enough.Async.AsyncLock();
        private static readonly object lockObj = new object();

        private readonly IsolatedStorageFile storageFile;

        #region 提供单例的支持
          
        public static IStorageHelper Instance { get; private set; }

        public static object LockObject;

        static IsolatedStorageHelper()
        {
            Instance = new IsolatedStorageHelper();
            LockObject = new object();
        }

        private IsolatedStorageHelper()
        {
            storageFile = IsolatedStorageFile.GetUserStoreForApplication();
        }

        #endregion

        public Stream ReadFile(string filePath)
        {
            lock (lockObj)
            {
                if (!storageFile.FileExists(filePath))
                {
                    throw new FileNotFoundException(string.Format("没有找到文件:{0}", filePath));
                }

                using (var fs = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, storageFile))
                {
                    var stream = new MemoryStream();
                    fs.CopyTo(stream);

                    stream.Seek(0, SeekOrigin.Begin);
                    return stream;
                }
            }
        }

        public string ReadText(string filePath)
        {
            lock (lockObj)
            {
                using (var stream = new IsolatedStorageFileStream(filePath, FileMode.Open, storageFile))
                {
                    using (var r = new StreamReader(stream))
                    {
                        return r.ReadToEnd();
                    }
                }
            }
        }

        public void WriteFile(Stream stream, string filePath, bool replace = false)
        {
            WriteFile(ToBytes(stream), filePath, replace);
        }

        public void WriteFile(byte[] data, string filePath, bool replace = false)
        {
            lock (lockObj)
            {
                var directory = Path.GetDirectoryName(filePath);
                if (directory != null)
                {
                    directory = directory.Replace("\\", "/");
                    if (!storageFile.DirectoryExists(directory))
                    {
                        //如果目录不存在,则创建
                        storageFile.CreateDirectory(directory);
                    }
                }

                if (storageFile.FileExists(filePath))
                {
                    if (replace)
                    {
                        storageFile.DeleteFile(filePath);
                    }
                    else
                    {
                        return;
                    }
                }

                using (var fs = new IsolatedStorageFileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, storageFile))
                {
                    fs.Write(data, 0, data.Length);
                }
            }
        }

        public void WriteText(string text, string filePath, bool replace = false)
        {
            WriteFile(Encoding.UTF8.GetBytes(text), filePath, replace);
        }

        public bool FileExists(string filePath)
        {
            lock (lockObj)
            {
                return storageFile.FileExists(filePath);
            }
        }

        public bool DirectoryExists(string directory)
        {
            lock (lockObj)
            {
                return storageFile.DirectoryExists(directory);
            }
        }

        public bool DeleteFile(string filePath)
        {
            lock (lockObj)
            {
                if (!storageFile.FileExists(filePath)) return false;
                storageFile.DeleteFile(filePath);
                return true;
            }
        }

        public bool DeleteDirectory(string directory, bool isDeleteAll)
        {
            lock (lockObj)
            {
                if (storageFile.GetFileNames(directory).Length + storageFile.GetDirectoryNames(directory).Length > 0)
                {
                    if (isDeleteAll)
                    {
                        DeleteDirectory(directory);
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    storageFile.DeleteDirectory(directory);
                    return true;
                }
            }
        }

        public bool CreateDirectory(string directory)
        {
            lock (lockObj)
            {
                if (storageFile.DirectoryExists(directory)) return false;
                storageFile.CreateDirectory(directory);
                return true;
            }
        }

        public long GetFileLength(string filePath)
        {
            lock (lockObj)
            {
                if (storageFile.FileExists(filePath))
                {
                    return storageFile.OpenFile(filePath, FileMode.Open, FileAccess.Read).Length;
                }
                throw new FileNotFoundException(string.Format("没有找到文件:{0}", filePath));
            }
        }


        public string[] GetFiles(string directory)
        {
            lock (lockObj)
            {
                var files = storageFile.GetFileNames(directory);
                return files.Select(f => directory + f).ToArray();
            }
        }

        public string[] GetDirectories(string directory)
        {
            lock (lockObj)
            {
                var folders = storageFile.GetDirectoryNames(directory);
                return folders.Select(f => directory + f).ToArray();
            }
        }

        public void Serialize<T>(string filePath, T obj)
        {
            lock (lockObj)
            {
                var directory = Path.GetDirectoryName(filePath);
                if (directory != null)
                {
                    directory = directory.Replace("\\", "/");
                    if (!storageFile.DirectoryExists(directory))
                    {
                        //如果目录不存在,则创建
                        storageFile.CreateDirectory(directory);
                    }
                }

                if (storageFile.FileExists(filePath))
                {
                    storageFile.DeleteFile(filePath);
                }

                using (
                    var fs = new IsolatedStorageFileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write,
                        FileShare.None, storageFile))
                {
                    var serializer = new XmlSerializer(obj.GetType());
                    serializer.Serialize(fs, obj);
                }
            }
        }

        public T DeSerialize<T>(string filePath)
        {
            lock (lockObj)
            {
                if (!storageFile.FileExists(filePath))
                {
                    throw new FileNotFoundException(string.Format("没有找到文件:{0}", filePath));
                }
                var serializer = new XmlSerializer(typeof (T));
                using (var fs = storageFile.OpenFile(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    return (T) serializer.Deserialize(fs);
                }
            }
        }

        public void CopyPackageFileToLocal(string source, string target = null, bool replace = false)
        {
            using (var stream = Application.GetResourceStream(new Uri(source, UriKind.Relative)).Stream)
            {
                WriteFile(stream, target ?? source, replace);
            }
        }

        public void CopyPackageFolderToLocal(string source, string target = null, bool replace = false)
        {
            throw new NotImplementedException("IsolatedStorageFile不支持拷贝安装文件夹");
        }

        public Stream GetResourceStream(string filePath)
        {
            return Application.GetResourceStream(new Uri(filePath, UriKind.Relative)).Stream;
        }

        public async Task<Stream> ReadFileAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() => ReadFile(filePath));
            }
        }

        public async Task<string> ReadTextAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() => ReadText(filePath));
            }
        }

        public async Task WriteFileAsync(Stream stream, string filePath, bool replace = false)
        {
            await WriteFileAsync(ToBytes(stream), filePath, replace);
        }

        public async Task WriteFileAsync(byte[] data, string filePath, bool replace = false)
        {
            using (await asyncLock.LockAsync())
            {
                await Task.Factory.StartNew(() => WriteFile(data, filePath, replace));
            }
        }

        public async Task WriteTextAsync(string text, string filePath, bool replace = false)
        {
            await WriteFileAsync(Encoding.UTF8.GetBytes(text), filePath, replace);
        }

        public async Task<bool> FileExistsAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() => FileExists(filePath));
            }
        }

        public async Task<bool> DirectoryExistsAsync(string directory)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() => DirectoryExists(directory));
            }
        }

        public async Task<bool> DeleteFileAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(() => DeleteFileAsync(filePath));
            }
        }

        public async Task<bool> DeleteDirectoryAsync(string directory, bool isDeleteAll = false)
        {
             using (await asyncLock.LockAsync())
             {
                 return await Task.Factory.StartNew(() => DeleteDirectory(directory, isDeleteAll));
             }
         
        }

        public async Task<bool> CreateDirectoryAsync(string directory)
        {
           using (await asyncLock.LockAsync())
           {
               return await Task.Factory.StartNew(() => CreateDirectory(directory));
           }
        }

        public async Task<ulong> GetFileLengthAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() => (ulong)GetFileLength(filePath));
            }
        }

        public async Task<string[]> GetFilesAsync(string directory)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() => GetFiles(directory));
            }
        }

        public async Task<string[]> GetDirectoriesAsync(string directory)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() => GetDirectories(directory));
            }
        }

        public async Task SerializeAsync<T>(string filePath, T obj)
        {
             using (await asyncLock.LockAsync())
             {
                 await Task.Factory.StartNew(() => Serialize(filePath, obj));
             }
        }

        public async Task<T> DeSerializeAsync<T>(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() => DeSerialize<T>(filePath));
            }
        }

        public async Task CopyPackageFileToLocalAsync(string source, string target = null, bool replace = false)
        {
             using (await asyncLock.LockAsync())
            {
                await Task.Factory.StartNew(() => CopyPackageFileToLocal(source, target, replace));
            }
        }

        public async Task CopyPackageFolderToLocalAsync(string source, string target = null, bool replace = false)
        {
            using (await asyncLock.LockAsync())
            {
                await Task.Factory.StartNew(() => CopyPackageFolderToLocal(source, target, replace));
            }
        }

        public async Task<Stream> GetResourceStreamAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await Task.Factory.StartNew(() =>
                    Application.GetResourceStream(new Uri(filePath, UriKind.Relative)).Stream);
            }
        }

        #region 辅助函数

        //递归删除文件夹
        private void DeleteDirectory(string directory)
        {
            var directories = storageFile.GetDirectoryNames(directory);
            foreach (var d in directories)
            {
                DeleteDirectory(string.Format("{0}{1}/", directory, d));
            }
            var files = storageFile.GetFileNames(directory);
            foreach (var f in files)
            {
                storageFile.DeleteFile(f);
            }
        }

        private byte[] ToBytes(Stream stream)
        {
            if (stream.CanSeek)
            {
                stream.Seek(0, SeekOrigin.Begin);
            }
            var length = Convert.ToInt32(stream.Length);
            var data = new byte[length];
            stream.Read(data, 0, length);
            return data;
        }

        #endregion
    }
}
IsolatedStorageHelper

 

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Windows.ApplicationModel;
using Windows.Storage;
using Enough.Async;

namespace TestDemo
{
    public class StorageHelper : IStorageHelper
    {
        private static readonly AsyncLock asyncLock = new AsyncLock();

        #region 提供单例的支持
          
        public static IStorageHelper Instance { get; private set; }

        public static object LockObject;

        static StorageHelper()
        {
            Instance = new StorageHelper();
            LockObject = new object();
        }

        private StorageHelper()
        {
        }

        #endregion

        #region 同步方法(StorageFile不支持同步方法)

        public Stream ReadFile(string filePath)
        {
            throw new NotImplementedException();
        }

        public string ReadText(string filePath)
        {
            throw new NotImplementedException();
        }

        public void WriteFile(Stream stream, string filePath, bool replace = false)
        {
            throw new NotImplementedException();
        }

        public void WriteFile(byte[] data, string filePath, bool replace = false)
        {
            throw new NotImplementedException();
        }

        public void WriteText(string text, string filePath, bool replace = false)
        {
            throw new NotImplementedException();
        }

        public bool FileExists(string filePath)
        {
            throw new NotImplementedException();
        }

        public bool DirectoryExists(string directory)
        {
            throw new NotImplementedException();
        }

        public bool DeleteFile(string filePath)
        {
            throw new NotImplementedException();
        }

        public bool DeleteDirectory(string directory, bool isDeleteAll = false)
        {
            throw new NotImplementedException();
        }

        public bool CreateDirectory(string directory)
        {
            throw new NotImplementedException();
        }

        public long GetFileLength(string filePath)
        {
            throw new NotImplementedException();
        }

        public string[] GetFiles(string directory)
        {
            throw new NotImplementedException();
        }

        public string[] GetDirectories(string directory)
        {
            throw new NotImplementedException();
        }

        public void Serialize<T>(string filePath, T obj)
        {
            throw new NotImplementedException();
        }

        public T DeSerialize<T>(string filePath)
        {
            throw new NotImplementedException();
        }

        public void CopyPackageFileToLocal(string source, string target = null, bool replace = false)
        {
            throw new NotImplementedException();
        }

        public void CopyPackageFolderToLocal(string source, string target = null, bool replace = false)
        {
            throw new NotImplementedException();
        }

        public Stream GetResourceStream(string filePath)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region 异步方法

        public async Task<Stream> ReadFileAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(async () =>
                {
                    try
                    {
                        filePath = filePath.Trim('/').Replace("/", "\\");

                        var file = await ApplicationData.Current.LocalFolder.GetFileAsync(filePath);

                        using (Stream stream = await file.OpenStreamForReadAsync())
                        {
                            return CopyStream(stream);
                        }
                    }
                    catch (FileNotFoundException)
                    {
                        throw new FileNotFoundException(string.Format("没有找到文件:{0}", filePath));
                    }
                });
            }
        }

        public async Task<string> ReadTextAsync(string filePath)
        {
            Debug.WriteLine("Read Begin");
            var text = string.Empty;
            using (var stream = await ReadFileAsync(filePath))
            {
                using (var reader = new StreamReader(stream))
                {
                    text = await reader.ReadToEndAsyncThread();
                }
            }
            Debug.WriteLine("Read Complete");

            return text;
        }

        public async Task WriteFileAsync(Stream stream, string filePath, bool replace = false)
        {
            await WriteFileAsync(ToBytes(stream), filePath, replace);
        }

        //只支持本地路径
        public async Task WriteFileAsync(byte[] data, string filePath, bool replace = false)
        {
            Debug.WriteLine("Write Begin!");

            using (await asyncLock.LockAsync())
            {
                await await Task.Factory.StartNew(async () =>
                {
                    try
                    {
                        //发现通过ms-appdata:///local/访问的方会出现问题,现改成通过下面方式访问文件
                        filePath = filePath.Trim('/').Replace("/", "\\");
                        var file = await ApplicationData.Current.LocalFolder.GetFileAsync(filePath);

                        if (replace)
                        {
                            await file.DeleteAsync();
                        }
                        else
                        {
                            return;
                        }
                    }
                    catch (FileNotFoundException)
                    {
                        //文件不存在
                    }

                    //创建文件
                    var fileName = filePath.Trim('/').Replace("/", "\\");
                    var storageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName);
                    using (var stream = await storageFile.OpenStreamForWriteAsync())
                    {
                        stream.Write(data, 0, data.Length);
                    }
                });
            }
            
            Debug.WriteLine("Write Complete!");
        }

        public async Task WriteTextAsync(string text, string filePath, bool replace = false)
        {
            await WriteFileAsync(Encoding.UTF8.GetBytes(text), filePath, replace);
        }

        public async Task<bool> FileExistsAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(async () =>
                {
                    try
                    {
                        filePath = filePath.Trim('/').Replace("/", "\\");
                        await ApplicationData.Current.LocalFolder.GetFileAsync(filePath);
                        return true;
                    }
                    catch (Exception)
                    {
                        Debug.WriteLine(filePath);
                        return false;
                    }
                });
            }
        }

        public async Task<bool> DirectoryExistsAsync(string directory)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(async () =>
                {
                    try
                    {
                        directory = directory.Trim('/').Replace("/", "\\");
                        await ApplicationData.Current.LocalFolder.GetFolderAsync(directory);
                        return true;
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                });
            }
        }

        public async Task<bool> DeleteFileAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(async () =>
                {
                    try
                    {
                        var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(string.Format("ms-appdata:///local/{0}", filePath), UriKind.Absolute));
                        await file.DeleteAsync();
                        return true;
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                });
            }
        }

        public async Task<bool> DeleteDirectoryAsync(string directory, bool isDeleteAll = false)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(async () =>
                {
                    try
                    {
                        directory = directory.Trim('/').Replace("/", "\\");
                        var folder = await ApplicationData.Current.LocalFolder.GetFolderAsync(directory);
                        await folder.DeleteAsync();
                        return true;
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                });
            }

        }

        public async Task<bool> CreateDirectoryAsync(string directory)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(async () =>
                {
                    try
                    {
                        directory = directory.Trim('/').Replace("/", "\\");
                        await ApplicationData.Current.LocalFolder.CreateFolderAsync(directory, CreationCollisionOption.OpenIfExists);
                        return true;
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                });
            }
        }

        public async Task<ulong> GetFileLengthAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(async () =>
                {
                    var file = await
                        StorageFile.GetFileFromApplicationUriAsync(new Uri(string.Format("ms-appdata:///local/{0}", filePath),
                            UriKind.Absolute));

                    return (await file.OpenReadAsync()).Size;
                });
            }
        }

        public async Task<string[]> GetFilesAsync(string directory)
        {
            directory = directory.Trim('/').Replace("/", "\\");
            var folder = await ApplicationData.Current.LocalFolder.GetFolderAsync(directory);
            var files = await folder.GetFilesAsync();
            return files.ToList()
                .Select(f => f.Path.Replace(ApplicationData.Current.LocalFolder.Path, string.Empty).Trim('\\').Replace("\\", "/"))
                .ToArray();
        }

        public async Task<string[]> GetDirectoriesAsync(string directory)
        {
            directory = directory.Trim('/').Replace("/", "\\");
            var folder = await ApplicationData.Current.LocalFolder.GetFolderAsync(directory);
            var files = await folder.GetFoldersAsync();
            return files.ToList()
                .Select(f => f.Path.Replace(ApplicationData.Current.LocalFolder.Path, string.Empty).Trim('\\').Replace("\\", "/"))
                .ToArray();
        }

        public async Task SerializeAsync<T>(string filePath, T obj)
        {
            var stream = new MemoryStream();
            var serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(stream, obj);
            stream.Seek(0, SeekOrigin.Begin);
            await WriteFileAsync(stream, filePath, true);
        }

        public async Task<T> DeSerializeAsync<T>(string filePath)
        {
            using (var stream = await ReadFileAsync(filePath))
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(stream);
            }
        }

        public async Task CopyPackageFileToLocalAsync(string source, string target = null, bool replace = false)
        {
            using (var stream = await GetResourceStreamAsync(source))
            {
                target = target ?? source;
                await WriteFileAsync(stream, target, replace);
            }
        }

        public async Task CopyPackageFolderToLocalAsync(string source, string target = null, bool replace = false)
        {

            source = source.Trim('/').Replace("/", "\\");
            target = target != null ? target.Trim('/').Replace("/", "\\") : source;

            var sourseFolder = await Package.Current.InstalledLocation.GetFolderAsync(source);

            //创建目标文件夹
            var targetFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(target, CreationCollisionOption.OpenIfExists);

            await CopyPackageFolderToLocalAsync(sourseFolder, targetFolder, replace);
        }

        public async Task CopyPackageFolderToLocalAsync(StorageFolder source, StorageFolder target, bool replace = false)
        {
            var folders = await source.GetFoldersAsync();
            foreach (var storageFolder in folders)
            {
                var targetFolder = await target.CreateFolderAsync(storageFolder.Name, CreationCollisionOption.OpenIfExists);
                await CopyPackageFolderToLocalAsync(storageFolder, targetFolder, replace);
            }

            var files = await source.GetFilesAsync();
            foreach (var storageFile in files)
            {
                try
                {
                    await storageFile.CopyAsync(target, storageFile.Name, replace
                        ? NameCollisionOption.ReplaceExisting
                        : NameCollisionOption.FailIfExists);
                }
                catch (Exception)
                {
                    //文件已存在(不替换),抛出异常
                }
            }
        }

        public async Task<Stream> GetResourceStreamAsync(string filePath)
        {
            using (await asyncLock.LockAsync())
            {
                return await await Task.Factory.StartNew(async () =>
                {
                    filePath = filePath.Trim('/').Replace("/", "\\");

                    //发现通过ms-appx:///访问的方会出现问题,现改成通过下面方式访问文件
                    var f = await Package.Current.InstalledLocation.GetFileAsync(filePath);
                    using (Stream stream = await f.OpenStreamForReadAsync())
                    {
                        return CopyStream(stream);
                    }
                });
            }
        }
        
        #endregion

        #region 辅助函数

        private static byte[] ToBytes(Stream stream)
        {
            if (stream.CanSeek)
            {
                stream.Seek(0, SeekOrigin.Begin);
            }
            int length = Convert.ToInt32(stream.Length);
            var data = new byte[length];
            stream.Read(data, 0, length);
            return data;
        }

        public Stream CopyStream(Stream stream)
        {
            if (stream.CanSeek)
            {
                stream.Seek(0, SeekOrigin.Begin);
            }
            var tempStream = new MemoryStream();
            stream.CopyTo(tempStream);
            tempStream.Seek(0, SeekOrigin.Begin);
            return tempStream;
        }

        #endregion
    }
}
StorageHelper

 

 

参考链接

  https://asynclock.codeplex.com/

  http://stackoverflow.com/questions/21246610/access-a-storagefolder-with-ms-appdata

  http://stackoverflow.com/questions/17935624/storagefile-50-times-slower-than-isolatedstoragefile

 

 

个人能力有限,如果有更好的实现,可以给我留言

转载请注明出处:http://www.cnblogs.com/bomo/p/3942750.html

 

posted @ 2014-08-28 21:56  bomo  阅读(1103)  评论(0编辑  收藏  举报