概要: WebRequest を使用して、自分のインターネット DNS から FTP で XML ファイルをダウンロードしています。FTP サーバーからファイルをダウンロードするアプリをコーディングするのはこれが初めてです。XML ファイルを使用できなくするダウンロードで、一貫性のない破損が多数発生しています。ファイルをダウンロードするための実際のコードは、「Windows ストア アプリの FTP ファイル ダウンローダー」という名前の Microsoft Windows 8 サンプルから取得されます。この Windows 8 のサンプルを使用しても同じ破損が発生することがわかったので、必ずしも私のコードに別のものがあるとは限りません。
はじめ に 私の Windows ストア アプリは、そのデータに XML ファイルを使用します。このデータは、もともと Excel から取得されたものです。このデータを毎月更新し、アプリのユーザーがシームレスに利用できるようにする必要があります。この目的のために、XML データ ファイルの最新バージョンを保存する Web サイトを作成しました。これらのファイルは、Filezilla を使用してバイナリ転送モードでアップロードされています (ちなみに、ASCII 形式でアップロードされた場合、WebRequest がファイルからすべての CR/LF を削除し、それらを役に立たなくすることがわかりました)。
私のアプリは、Microsoft のサンプルで提供されている、Windows ストア アプリの FTP ファイル転送用のコードを使用しています。次のようになります。
using System;
using System.IO;
using System.Net;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
namespace CSWindowsStoreAppFTPDownloader.FTP
{
public static class FTPClient
{
/// <summary>
/// Download a single file from FTP server using WebRequest.
/// </summary>
public static async Task<DownloadCompletedEventArgs>
DownloadFTPFileAsync(FTPFileSystem item,
StorageFile targetFile, ICredentials credential)
{
var result = new DownloadCompletedEventArgs
{
RequestFile = item.Url,
LocalFile = targetFile,
Error=null
};
// This request is FtpWebRequest in fact.
WebRequest request = WebRequest.Create(item.Url);
if (credential != null)
{
request.Credentials = credential;
}
request.Proxy = WebRequest.DefaultWebProxy;
// Set the method to Download File
request.Method = "RETR";
try
{
// Open the file for write.
using (IRandomAccessStream fileStream =
await targetFile.OpenAsync(FileAccessMode.ReadWrite))
{
// Get response.
using (WebResponse response = await request.GetResponseAsync())
{
// Get response stream.
using (Stream responseStream = response.GetResponseStream())
{
byte[] downloadBuffer = new byte[2048];
int bytesSize = 0;
// Download the file until the download is completed.
while (true)
{
// Read a buffer of data from the stream.
bytesSize = responseStream.Read(downloadBuffer, 0,
downloadBuffer.Length);
if (bytesSize == 0)
{
break;
}
// Write buffer to the file.
await fileStream.WriteAsync(downloadBuffer.AsBuffer());
}
}
}
}
}
catch (Exception ex)
{
result.Error=ex;
}
return result;
}
}
}
問題 XML ファイルの形式は次のとおりです。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Table>
<Row>
<Month>JAN</Month>
<Year>1996</Year>
<RPI>74.6</RPI>
</Row>
<Row>
<Month>FEB</Month>
<Year>1996</Year>
<RPI>75.1</RPI>
</Row>
...
</Table>
ただし、MS サンプル コードを使用して小さな整形式の XML ファイルをダウンロードすると、次のように終了タグが常に破損します。
<Row>
<Month>APR</Month>
<Year>2013</Year>
<RPI>114.92</RPI>
</Row>
</Table>/RPI>
</Row>
<Row>
<Month>APR</Month>
<Year>2011</Year>
<RPI>111.33</RPI>
</Row>
<Row>
<Month>MAY</
このコードが Microsoft 自身のサイトからのものであるという事実は、私には少し気になります。FTP サーバー上のファイルに何か問題がある可能性はありますか? バイナリ転送モードを使用して Filezilla でこれらをダウンロードしても問題ありません。以前の投稿を確認すると、バイナリ対 ASCII が問題であることがわかりますが、WebRequest には UseBinary プロパティがありません (Windows 8 で使用できない FTPWebRequest とは異なります)。
次の回避策を試しました。
- WebResponse の読み取りと出力ストリームへの書き込みに使用されるバッファー サイズを変更しました。
- 読み取り/書き込みペアごとにバッファを新しい byte[] 配列に再初期化する - 効果なし
- byte[] バッファの値を 0 に設定 - これにより、終了タグの破損が解消されましたが、XML の他のギャップがランダムに表示されました
明らかに次善の策であるこのレベルの回避策まで下がらなければならないとは思いません。ここで何が問題なのか知っている人はいますか?ありがとうございました。