サーバーから画像をダウンロードし、画像がまだローカルに保存されていない場合はローカルに保存するアプリがあります。この例のために、同じ名前の画像がいくつかあるとしましょう。一度だけダウンロードして一度だけ保存したい。現時点では、私のアプリは要求されるたびにそれらをダウンロードしています - imageX.png のサーバーに対して行われた引数 10 の要求のために。リクエストが戻ってくると、アプリはそれらをアプリケーション データ フォルダーに imageX.png として保存しようとします。複数のスレッドが同時に同じファイルに書き込もうとしているため、これが私の問題の始まりです。
ここに私が現在持っているコードがあります
public static async Task<BitmapImage> GetBitmapImage( string folderName, string fileName )
{
if( await FileExists( "\\Assets\\" + folderName, fileName ) )
{
return new BitmapImage( new Uri( Package.Current.InstalledLocation.Path + "/Assets/" + folderName + "/" + fileName, UriKind.RelativeOrAbsolute ) );
}
else
{
// Download and save locally
HttpClient httpClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage( HttpMethod.Get, "http://www.mywebsite.com/request.php?action=getImage&name=" + WebUtility.UrlEncode( fileName ) );
HttpResponseMessage response = await httpClient.SendAsync( request, HttpCompletionOption.ResponseHeadersRead );
BitmapImage image = new BitmapImage();
if( response.IsSuccessStatusCode )
{
InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();
DataWriter writer = new DataWriter( randomAccessStream.GetOutputStreamAt( 0 ) );
writer.WriteBytes( await response.Content.ReadAsByteArrayAsync() );
await writer.StoreAsync();
await image.SetSourceAsync( randomAccessStream );
var folderObj = await StorageFolder.GetFolderFromPathAsync( Package.Current.InstalledLocation.Path + "\\Assets\\" + folderName );
var imageFile = await folderObj.CreateFileAsync( fileName, CreationCollisionOption.ReplaceExisting );
var fs = await imageFile.OpenAsync( FileAccessMode.ReadWrite );
writer = new DataWriter( fs.GetOutputStreamAt( 0 ) );
writer.WriteBytes( await response.Content.ReadAsByteArrayAsync() );
await writer.StoreAsync();
writer.DetachStream();
await fs.FlushAsync();
}
return image;
}
}
私が必要だと思うのは、前のスレッドがタスクを完了し、必要に応じてディスクに保存されるまで、「if FileExists」の前にスレッドを停止することです。スレッドの残りの部分は、FileExists 呼び出しで即座に true を返します。