ファイルのアップロード方法 (HTML)

[この記事は、Windows ランタイム アプリを作成する Windows 8.x および Windows Phone 8.x 開発者を対象としています。Windows 10 向けの開発を行っている場合は、 「最新のドキュメント」をご覧ください]

ここでは、デバイスからインターネットにデータやファイルをアップロードする方法について説明します。

このトピックで説明する API を使うと、アプリが Web サービスとやり取りして、写真、音楽、ビデオなどの一般的なメディア形式を使用または共有できるようになります。

または、操作の持続期間内にアプリの複数回の一時停止やネットワークの可用性の変化が発生する可能性がある、サイズの大きいアップロード、ストリーム ベースの転送、マルチパートの転送の場合 (ビデオ、音楽、サイズの大きい画像など)、アプリでBackground Transferを使用できます。

バックグラウンド転送の概要については、「バックグラウンドでのデータの転送」をご覧ください。

必要条件

JavaScript を使った Windows ストア アプリの作成についての一般的なヘルプは、「JavaScript を使った初めての Windows ランタイム アプリの作成」をご覧ください。このトピックでは、JavaScript の promise を使って非同期操作も実行します。このプログラミング パターンについて詳しくは、promise を使った JavaScript での非同期プログラミングに関するページをご覧ください。

アプリをネットワークに対応させるには、プロジェクトの Package.appxmanifest ファイルで該当する機能を設定する必要があります。 それぞれのネットワーク機能の定義について詳しくは、「ネットワーク分離機能を構成する方法」をご覧ください。

以下のバックグラウンド転送例は JavaScript で記述されており、バックグラウンド転送のサンプルに基づいています。

バックグラウンド転送のアップロード操作

バックグラウンド転送を使う場合、アップロードは UploadOperation として存在し、操作の再起動やキャンセルに使われる多くの制御メソッドを公開します。 アプリのイベント (一時停止、終了など) や接続の変更は、UploadOperation を通じてシステムによって自動的に処理されます。アップロードは、アプリの一時停止中も続行し、アプリの終了以降は一時停止して保持されます。また、CostPolicy プロパティを設定することで、従量制課金接続がインターネット接続のために使われている間もアプリがアップロードを開始するかどうかを指定します。

以下に、基本的なアップロードを作成および初期化する例と、前のアプリ セッションから続いている操作を列挙および再び取り込む例を示します。

ファイルをアップロードする

アップロードの作成は、BackgroundUploader から始めます。このクラスは、アプリで結果の UploadOperation を作成する前に、そのアップロードの構成を可能にするメソッドを提供するために使われます。次の例は、必要な Uri オブジェクトと StorageFile オブジェクトを使ってこれを行う方法を示しています。

  1. アップロードするファイルと送信先の特定

    UploadOperation の作成を始める前に、アップロード先となる場所の URI とアップロードされるファイルを識別する必要があります。次の例では、UI 入力からの文字列を使って uriString の値が設定され、PickSingleFileAsync 操作で返される StorageFile オブジェクトを使って file の値が設定されます。

    function uploadFile() {
        var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
        filePicker.fileTypeFilter.replaceAll(["*"]);
    
        filePicker.pickSingleFileAsync().then(function (file) {
            if (!file) {
                printLog("No file selected");
                return;
            }
    
            var upload = new UploadOp();
            var uriString = document.getElementById("serverAddressField").value;
            upload.start(uriString, file);
    
            // Store the upload operation in the uploadOps array.
            uploadOperations.push(upload);
        });
    }
    
  2. アップロード操作の作成と初期化

    前の手順では、uriStringfile の値が次に示す例の UploadOp のインスタンスに渡されました。これらの値は、新しいアップロード操作を構成し開始するために使われます。まず、uriString が解析されて、要求された Uri オブジェクトが作成されます。

    そして、与えられた StorageFile (file) のプロパティが BackgroundUploader で使われて要求ヘッダーが設定され、SourceFile プロパティに StorageFile オブジェクトが設定されます。次に、SetRequestHeader メソッドが呼び出され、文字列として提供されたファイル名と StorageFile.Name プロパティが挿入されます。

    最後に、BackgroundUploader によって UploadOperation (upload) が作成されます。

    function UploadOp() {
        var upload = null;
        var promise = null;
    
        this.start = function (uriString, file) {
            try {
    
                var uri = new Windows.Foundation.Uri(uriString);
                var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
    
                // Set a header, so the server can save the file (this is specific to the sample server).
                uploader.setRequestHeader("Filename", file.name);
    
                // Create a new upload operation.
                upload = uploader.createUpload(uri, file);
    
                // Start the upload and persist the promise to be able to cancel the upload.
                promise = upload.startAsync().then(complete, error, progress);
            } catch (err) {
                displayError(err);
            }
        };
        // On application activation, reassign callbacks for a upload
        // operation persisted from previous application state.
        this.load = function (loadedUpload) {
            try {
                upload = loadedUpload;
                promise = upload.attachAsync().then(complete, error, progress);
            } catch (err) {
                displayError(err);
            }
        };
    }
    

    JavaScript の promise を使って定義した非同期メソッドの呼び出しに注意してください。最後の例には次の行があります。

    promise = upload.startAsync().then(complete, error, progress);
    

    非同期メソッドの後に then ステートメントが続いています。このステートメントでは、非同期メソッドの呼び出しの結果が返されたときに呼び出される、アプリで定義されたメソッドを指定しています。このプログラミング パターンについて詳しくは、「プロミスを使った JavaScript での非同期プログラミング」をご覧ください。

複数のファイルをアップロードする

  1. アップロードするファイルと送信先の特定

    単一の UploadOperation で複数のファイルを転送するシナリオでは、処理は通常どおり、最初に必要なアップロード先 URI とローカル ファイルの情報を指定することから始まります。前のセクションの例と同様に、URI はエンド ユーザーが文字列で指定します。また、FileOpenPicker を使って、ユーザー インターフェイスからファイルを指定する機能も提供できます。ただし、このシナリオでは、アプリで代わりに PickMultipleFilesAsync メソッドを呼び出して、UI から複数のファイルを選ぶことができるようにする必要があります。

    
    function uploadFiles() {
       var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
       filePicker.fileTypeFilter.replaceAll(["*"]);
    
       filePicker.pickMultipleFilesAsync().then(function (files) {
          if (files === 0) {
             printLog("No file selected");
                return;
          }
    
          var upload = new UploadOperation();
          var uriString = document.getElementById("serverAddressField").value;
          upload.startMultipart(uriString, files);
    
          // Persist the upload operation in the global array.
          uploadOperations.push(upload);
       });
    }
    
  2. 指定されたパラメーターに基づくオブジェクトの作成

    次の 2 つの例では、前の手順の最後に呼び出された単一のメソッド例 startMultipart に含まれているコードを使っています。わかりやすくするために、BackgroundTransferContentPart オブジェクトの配列を作るメソッドのコードは、結果の UploadOperation を作るコードから分割されています。

    最初に、ユーザーが指定した URI 文字列を Uri として初期化します。次に、このメソッドに渡された IStorageFile オブジェクト (files) の配列を反復処理し、配列内の各オブジェクトを使って新しい BackgroundTransferContentPart オブジェクトを作り、そのオブジェクトを contentParts 配列に配置します。

    
    upload.startMultipart = function (uriString, files) {
        try {
            var uri = new Windows.Foundation.Uri(uriString);
            var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
    
            var contentParts = [];
            files.forEach(function (file, index) {
                var part = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart("File" + index, file.name);
                part.setFile(file);
                contentParts.push(part);
            });
    
  3. マルチパート アップロード操作の作成と初期化

    contentParts 配列には、アップロード用の各 IStorageFile を表す BackgroundTransferContentPart オブジェクトがすべて含まれているため、要求の送信先を示す Uri を使って CreateUploadAsync を呼び出すことができます。

            // Create a new upload operation.
            uploader.createUploadAsync(uri, contentParts).then(function (uploadOperation) {
    
               // Start the upload and persist the promise to be able to cancel the upload.
               upload = uploadOperation;
               promise = uploadOperation.startAsync().then(complete, error, progress);
            });
    
         } catch (err) {
             displayError(err);
         }
     };
    

持続している操作を起動時に列挙する

UploadOperation が完了するか取り消されると、関連するシステム リソースがすべて解放されます。ただし、これらのイベントのどちらかが発生する前にアプリが終了した場合、アクティブな操作は一時停止され、それぞれに関連付けられているリソースは占有されたままになります。これらの操作が列挙されずに次のアプリ セッションに再び取り込まれると、それらの操作は完了せず、デバイス リソースを占有したままとなります。

  1. 持続している操作を列挙する関数を定義する前に、返される UploadOperation オブジェクトを格納する配列を作成する必要があります。

    var uploadOperations = [];
    
  2. 次に、持続している操作を列挙してそれらを配列に格納する関数を定義します。 UploadOperation に対するコールバックを再割り当てするために呼び出される load メソッドがアプリの終了以降も持続する場合は、このセクションでこの後定義する UploadOp クラス内にあります。

    function Windows.Networking.BackgroundTransfer.BackgroundUploader.getCurrentUploadsAsync() {
        .then(function (uploads) {
            for (var i = 0; i < uploads.size; i++) {
                var upload = new UploadOp();
                upload.load(uploads[i]);
                uploadOperations.push(upload);
            }
        }
    };
    

      

    Windows Phone ストア アプリでは、バックグラウンド転送はアプリがフォアグラウンドでない場合でも引き続き実行されます。アプリはこのシナリオで動作していないので、転送の完了時に通知を受け取りません。アプリの再開時に、完了した転送の進行状況をそのままチェックすると、状態は BackgroundTransferStatus.Running になります。ただし、上のコード例のように、転送に接続すると、タスク完了ハンドラーが起動し、転送状態が更新されます。

要求のタイムアウト

次の 2 つの主要接続タイムアウト シナリオを考慮する必要があります。

  • 転送のために新しい接続を確立する場合、5 分以内に接続が確立しないと、接続要求は中止されます。

  • 接続が確立された後、2 分以内で応答を受け取らなかった HTTP 要求メッセージは中止されます。

  どちらのシナリオにおいても、バックグラウンド転送はインターネット接続があることを前提に、最高 3 回まで自動的に要求を再試行します。インターネット接続が検出されないと、検出されるまで別の要求は待機します。

 

デバッグのガイダンス

Microsoft Visual Studio でデバッグ セッションを停止することは、アプリを閉じることに相当します。PUT によるアップロードは一時停止され、POST によるアップロードは終了されます。デバッグ時であっても、アプリでは、持続しているアップロードを列挙し、再実行や取り消しを行うことができる必要があります。たとえば、そのデバッグ セッションで以前の操作が重要ではない場合、アプリの起動時に、列挙された持続しているアップロード操作をアプリで取り消すことができます。

デバッグ セッションでアプリの起動時にダウンロードやアップロードを列挙する際、そのデバッグ セッションで以前の操作が重要ではない場合、列挙された操作をアプリで取り消すことができます。アプリ マニフェストの変更など、Visual Studio プロジェクトの更新があり、アプリがアンインストールされ、もう一度展開された場合、GetCurrentUploadsAsync は、前のアプリの展開を使って作成された操作を列挙できないことに注意してください。

詳しくは、「Windows ストア アプリのデバッグとテスト」をご覧ください。

開発時にバックグラウンド転送を使うと、完了したアクティブな転送操作の内部キャッシュが同期しなくなる状況が発生する可能性があります。このため、新しい転送操作を開始できない場合や、既存の操作や BackgroundTransferGroup オブジェクトを処理できない場合があります。状況によっては、既存の操作を処理しようとすると、クラッシュの原因となる可能性があります。これは、TransferBehavior プロパティが Parallel に設定されている場合に発生する可能性があります。この問題は、開発中に特定のシナリオでのみ発生し、アプリのエンド ユーザーには適用されません。

Visual Studio を使う 4 つのシナリオで、この問題が発生する可能性があります。

  • 既にあるプロジェクトと同じアプリ名を持つ新しいプロジェクトを、別の言語で作成する (C++ から C# など)。
  • 既にあるプロジェクトのターゲット アーキテクチャを変更する (x86 から x64 など)。
  • 既にあるプロジェクトのカルチャを変更する (ニュートラルから en-US など)。
  • 既にあるプロジェクトのパッケージ マニフェストで機能を追加または削除する (エンタープライズ認証を追加するなど)。

機能を追加または削除するマニフェストの更新など、通常のアプリのサービスでは、アプリのエンド ユーザーに対する展開でこの問題は発生しません。

この問題を回避するには、アプリのすべてのバージョンを完全にアンインストールし、新しい言語、アーキテクチャ、カルチャ、または機能をもう一度展開します。この操作は、スタート画面で行うか、PowerShell と Remove-AppxPackage コマンドレットを使って行うことができます。

要約と次のステップ

このトピックでは、JavaScript で Background Transfer API を使ってファイルをアップロードする方法について説明しました。

Windows ストア アプリでファイルをダウンロードすることもできます。主要概念とサンプルについては、「ファイルのダウンロード方法」をご覧ください。

関連トピック

その他

接続情報とデータ プラン情報へのアクセス

promise を使った JavaScript での非同期プログラミングに関する記事

JavaScript を使った初めての Windows ランタイム アプリの作成

ネットワーク分離機能を構成する方法

WinJS.xhr によるファイルのダウンロード方法

リファレンス

BackgroundUploader

UploadOperation

Windows.Networking.BackgroundTransfer

サンプル

バックグラウンド転送のサンプルに関するページ

HttpClient のサンプル

ファイルのダウンロード方法

Windows.Networking.BackgroundTransfer

バックグラウンド転送のサンプルに関するページ