14-08-29 12:32更新:修復StorageHelper部分bughtml
WP8之後提供了StorageFile的方式訪問文件,StorageFile對文件的操做只提供了異步的支持,包括WP8.1 RT也沒有對同步讀寫文件的支持,能夠看出異步在移動開發中的重要性,並且Win8也是經過StorageFile進行文件操做的安全
跟WP7上的IsolatedStorageFile相比,StorageFile使用起來並不方便,最近總結了一些資料,寫了一個通用的類庫app
StorageFile默認是線程不安全的,若是多個線程同時對文件進行讀寫會拋出異常,例如多圖的場景比較常見異步
讓StorageFile使用起來更加方便,同時提供了線程安全的異步操做,同時也對IsolatedStorageFile(Silverlight)進行了封裝async
1、StorageFile要點:ide
StorageFile函數
一、訪問文件(兩種方式)測試
//訪問安裝目錄下的test.txt文件,若是不存在,會拋出FileNotFoundException異常 //一、訪問當前目錄下的文件 var folder = Package.Current.InstalledLocation; var storageFile = await folder.GetFileAsync("test.txt"); //二、經過Uri訪問文件,Uri爲絕對路徑 storageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appdata:///local/test.txt", UriKind.Absolute)); //安裝文件目錄Uri前綴:ms-appx:/// //本地目錄Uri前綴:ms-appdata:///local/
二、沒有提供判斷文件是否存在的函數,這裏經過異常來判斷文件是否存在:this
try { await StorageFile.GetFileFromApplicationUriAsync(new Uri(string.Format("ms-appdata:///local/{0}", filePath), UriKind.Absolute)); return true; } catch (Exception) { return false; }
測試發現:使用上面的形式訪問文件會出現問題(好比文件明明存在,卻仍是會報FileNotFound異常),故StorageHelper不適用上面的形式,而是用經過文件夾訪問的形式訪問文件,能夠解決該問題,目前尚不清楚緣由spa
//發現經過ms-appdata:///local/訪問的方會出現問題,現改爲經過下面方式訪問文件 filePath = filePath.Trim('/').Replace("/", "\\"); var file = await ApplicationData.Current.LocalFolder.GetFileAsync(filePath);
三、建立文件
//若是文件已經存在,會拋出異常 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");
2、線程安全
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(); } } } } }
3、接口與實現
提供線程安全的異步操做(IsolatedStorageFile和StorageFile)
IStorageHelper:提供基本的文件操做相關方法
約定:
一、文件夾用'/'分割,
二、路徑不以斜槓'/'開頭
三、文件夾路徑以'/'結束
// ************************************************* // // 做者:bomo // 小組:WP開發組 // 建立日期:2014/8/28 21:49:04 // 版本號:V1.00 // 說明: 文件操做接口類,提供文件操做的相關方法 // // ************************************************* // // 修改歷史: // Date WhoChanges Made // 08/28/2014 bomo Initial creation // // ************************************************* // 約定: // 一、文件夾用'/'分割, // 二、路徑不以斜槓'/'開頭 // 三、文件夾路勁以'/'結束 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
我的能力有限,若是有更好的實現,能夠給我留言