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); } } } }
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(); } } } } }
三、接口与实现
提供线程安全的异步操作(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); } } }
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 } }
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 } }
参考链接
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
个人能力有限,如果有更好的实现,可以给我留言