• 【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

  • 相关阅读:
    C#之集合常用扩展方法与Linq
    PHP核心之MVC设计模式
    Javascript高级之变量
    Javascript高级之console调试
    Javascript高级之概述
    MySQL数据库之PDO扩展
    MySQL数据库之MySQL扩展
    MySQL数据库之数据库备份与还原
    MySQL数据库之预处理
    MySQL数据库之函数
  • 原文地址:https://www.cnblogs.com/bomo/p/3942750.html
Copyright © 2020-2023  润新知