【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

【WP8】线程安全的StorageHelper
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
【WP8】线程安全的StorageHelper
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不支持同步处理文件

辅助扩展类

【WP8】线程安全的StorageHelper
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

 

【WP8】线程安全的StorageHelper
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

 

【WP8】线程安全的StorageHelper
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

 

你可能感兴趣的:(线程安全)