ASP.NET Web ページ (Razor) サイトでのファイルの操作
作成者: Tom FitzMacken
この記事では、ASP.NET Web ページ (Razor) サイトでファイルの読み取り、書き込み、追加、削除、アップロードを行う方法について説明します。
Note
画像をアップロードして操作する場合 (反転やサイズ変更など)、「ASP.NET Web ページ サイトでのイメージの操作」を参照してください。
学習内容:
- テキスト ファイルを作成してデータを書き込む方法。
- 既存のファイルにデータを追加する方法。
- ファイルを読み取ってそこから表示する方法。
- Web サイトからファイルを削除する方法。
- ユーザーが 1 つのファイルまたは複数のファイルをアップロードできるようにする方法。
この記事で紹介する ASP.NET プログラミング機能を次に示します。
- ファイルを管理する方法を提供する
File
オブジェクト。FileUpload
ヘルパー。- パスとファイルの名前を操作できるメソッドを提供する
Path
オブジェクト。チュートリアルで使用するソフトウェアのバージョン
- ASP.NET Web ページ (Razor) 2
- WebMatrix 2
このチュートリアルは、WebMatrix 3 でも動作します。
テキスト ファイルの作成とデータの書き込み
Web サイトでデータベースを使用するだけでなく、ファイルを操作することもできます。 たとえば、サイトのデータを格納する簡単な方法としてテキスト ファイルを使用できます。 (データの格納に使用されるテキスト ファイルは、"フラット ファイル" と呼ばれることもあります。) テキスト ファイルは、.txt、.xml、.csv (コンマ区切り値) など、さまざまな形式にすることができます。
データをテキスト ファイルに格納する場合は、File.WriteAllText
メソッドを使用して、作成するファイルとそれに書き込むデータを指定できます。 この手順では、3 つの input
要素 (名、姓、メール アドレス) と [Submit] ボタンを使用したシンプルなフォームを含むページを作成します。 ユーザーがフォームを送信すると、ユーザーの入力がテキスト ファイルに格納されます。
App_Data という名前の新しいフォルダーを作成します (まだ存在しない場合)。
Web サイトのルートで、UserData.cshtml という名前の新しいファイルを作成します。
既存のコンテンツを次に置き換えます。
@{ var result = ""; if (IsPost) { var firstName = Request["FirstName"]; var lastName = Request["LastName"]; var email = Request["Email"]; var userData = firstName + "," + lastName + "," + email + Environment.NewLine; var dataFile = Server.MapPath("~/App_Data/data.txt"); File.WriteAllText(@dataFile, userData); result = "Information saved."; } } <!DOCTYPE html> <html> <head> <title>Write Data to a File</title> </head> <body> <form id="form1" method="post"> <div> <table> <tr> <td>First Name:</td> <td><input id="FirstName" name="FirstName" type="text" /></td> </tr> <tr> <td>Last Name:</td> <td><input id="LastName" name="LastName" type="text" /></td> </tr> <tr> <td>Email:</td> <td><input id="Email" name="Email" type="text" /></td> </tr> <tr> <td></td> <td><input type="submit" value="Submit"/></td> </tr> </table> </div> <div> @if(result != ""){ <p>Result: @result</p> } </div> </form> </body> </html>
この HTML マークアップにより、3 つのテキスト ボックスを含むフォームを作成します。 このコードでは、
IsPost
プロパティを使用して、処理を開始する前に、ページが送信されたかどうかを判断します。最初のタスクは、ユーザー入力を取得し、変数に代入することです。 その後、コードで個別の変数の値を 1 つのコンマ区切り文字列に連結し、別の変数に格納します。 コンマ区切り記号は引用符 (",") 内に含まれた文字列であることに注意してください。これは、作成する大きな文字列にコンマをリテラルとして埋め込んでいるためです。 連結するデータの末尾に
Environment.NewLine
を追加します。 これにより改行 (改行文字) が追加されます。 この連結をすべて使用して作成するのは、次のような文字列です。David,Jones,davidj@contoso.com
(末尾に非表示の改行がある場合。)
次に、データを格納するファイルの場所と名前を含む変数 (
dataFile
) を作成します。 場所を設定するには、特別な処理が必要です。 Web サイトでは、Web サーバー上のファイルに対して C:\Folder\File.txt のような絶対パスをコードで参照するのは不適切な方法です。 Web サイトを移動すると、絶対パスが正しくなくなります。 さらに、ホストされているサイト (自分のコンピューターではなく) では、通常、コードを記述するときに正しいパスが何であるかさえわかりません。しかし、(今のように、ファイルを書き込むために) 完全なパスが必要な場合があります。 解決策は、
Server
オブジェクトのMapPath
メソッドを使用することです。 これにより、Web サイトへの完全なパスが返されます。 Web サイトのルートのパスを取得するには、~
オペレーター (サイトの仮想ルートを表す) をMapPath
に対して使用します。 (~/App_Data/ などのサブフォルダー名を渡して、そのサブフォルダーのパスを取得することもできます。) その後、メソッドから返されるものに追加情報を連結して、完全なパスを作成できます。 この例では、ファイル名を追加します。 (ファイルとフォルダーのパスを操作する方法の詳細については、「Razor 構文を使用した ASP.NET Web プログラミングの概要」を参照してください。)ファイルは App_Data フォルダーに保存されます。 このフォルダーは、「ASP.NET Web ページ サイトでのデータベースの操作の概要」で説明されているように、データ ファイルを格納するために使用される ASP.NET の特殊なフォルダーです。
File
オブジェクトのWriteAllText
メソッドは、ファイルにデータを書き込みます。 このメソッドは 2 つのパラメーターを受け取ります。書き込み先ファイルの名前 (およびパス) と、書き込む実際のデータです。 最初のパラメーターの名前にプレフィックスとして@
文字が付いていることに注意してください。 これは、ASP.NET に逐語的な文字列リテラルを提供していること、"/" のような文字を特別な方法で解釈してはならないことを示します。 (詳細については、「Razor 構文を使用した ASP.NET Web プログラミングの概要」を参照してください。)Note
コードで App_Data フォルダーにファイルを保存するには、そのフォルダーに対する読み取り/書き込みアクセス許可がアプリケーションに必要です。 開発用コンピューターでは、これは通常問題ではありません。 ただし、ホスティング プロバイダーの Web サーバーにサイトを発行する場合は、それらのアクセス許可を明示的に設定することが必要になる場合があります。 ホスティング プロバイダーのサーバーでこのコードを実行し、エラーが発生した場合は、ホスティング プロバイダーに問い合わせて、それらのアクセス許可を設定する方法を確認してください。
ブラウザーでページを実行します。
フィールドに値を入力し、[Submit] をクリックします。
ブラウザーを閉じます。
プロジェクトに戻り、ビューを更新します。
data.txt ファイルを開きます。 フォームで送信したデータがファイル内にあります。
data.txt ファイルを閉じます。
既存のファイルへのデータの追加
前の例では、WriteAllText
を使用して 1 件のデータのみを含むテキスト ファイルを作成しました。 メソッドを再度呼び出して同じファイル名を渡すと、既存のファイルが完全に上書きされます。 ただし、ファイルを作成した後、多くの場合、ファイルの末尾に新しいデータを追加する必要があります。 これは、File
オブジェクトの AppendAllText
メソッドを使用して行うことができます。
Web サイトで、UserData.cshtml ファイルのコピーを作成し、そのコピーに Copy UserDataMultiple.cshtml という名前を付けます。
開始
<!DOCTYPE html>
タグの前のコード ブロックを次のコード ブロックに置き換えます。@{ var result = ""; if (IsPost) { var firstName = Request["FirstName"]; var lastName = Request["LastName"]; var email = Request["Email"]; var userData = firstName + "," + lastName + "," + email + Environment.NewLine; var dataFile = Server.MapPath("~/App_Data/data.txt"); File.AppendAllText (@dataFile, userData); result = "Information saved."; } }
このコードには、前の例から変更が 1 つ加えられています。
WriteAllText
を使用するのではなく、the AppendAllText
メソッドを使用します。 これらのメソッドは似ていますが、AppendAllText
はファイルの末尾にデータを追加する点が異なります。WriteAllText
と同様に、ファイルがまだ存在しない場合は、AppendAllText
でファイルが作成されます。ブラウザーでページを実行します。
フィールドの値を入力し、[Submit] をクリックします。
さらにデータを追加し、フォームをもう一度送信します。
プロジェクトに戻り、プロジェクト フォルダーを右クリックして、[最新の情報に更新] をクリックします。
data.txt ファイルを開きます。 入力した新しいデータが含まれるようになりました。
ファイルからのデータの読み取りと表示
テキスト ファイルにデータを書き込む必要がない場合でも、それからデータを読み取ることが必要な場合はあるでしょう。 これを行うには、File
オブジェクトをもう一度使用できます。 File
オブジェクトを使用すると、各行を個別に (改行で区切って) 読み取ったり、区切り方に関係なく個々の項目を読み取ったりできます。
この手順では、前の例で作成したデータを読み取って表示する方法を示します。
Web サイトのルートで、DisplayData.cshtml という名前の新しいファイルを作成します。
既存のコンテンツを次に置き換えます。
@{ var result = ""; Array userData = null; char[] delimiterChar = {','}; var dataFile = Server.MapPath("~/App_Data/data.txt"); if (File.Exists(dataFile)) { userData = File.ReadAllLines(dataFile); if (userData == null) { // Empty file. result = "The file is empty."; } } else { // File does not exist. result = "The file does not exist."; } } <!DOCTYPE html> <html> <head> <title>Reading Data from a File</title> </head> <body> <div> <h1>Reading Data from a File</h1> @result @if (result == "") { <ol> @foreach (string dataLine in userData) { <li> User <ul> @foreach (string dataItem in dataLine.Split(delimiterChar)) { <li>@dataItem</li > } </ul> </li> } </ol> } </div> </body> </html>
このコードは最初に次のメソッド呼び出しを使用して、前の例で作成したファイルを名前付きの
userData
変数に読み取ります。File.ReadAllLines(dataFile)
これを行うコードは、
if
ステートメント内部にあります。 ファイルを読み取る場合は、File.Exists
メソッドを使用して、ファイルが使用可能かどうかを最初に判断することをお勧めします。 このコードは、ファイルが空かどうかもチェックします。ページの本文には 2 つの
foreach
ループが含まれていて、1 つはもう一方の内側に入れ子になっています。 外側のforeach
ループは、データ ファイルから一度に 1 行ずつ取得します。 この場合、行はファイル内の改行によって定義されます。つまり、各データ項目は独自の行に配置されます。 外側のループは、順序付けられたリスト (<ol>
要素) の内側に新しい項目 (<li>
要素) を作成します。内側のループは、区切り記号としてコンマを使用して、各データ行を項目 (フィールド) に分割します。 (前の例に基づくと、各行に 3 つのフィールド (名、姓、メール アドレスがそれぞれコンマで区切られている) が含まれていることを意味します。) 内側のループでは、
<ul>
リストも作成され、データ行のフィールドごとに 1 つのリスト項目が表示されます。このコードは、配列と
char
データ型という 2 つのデータ型を使用する方法を示しています。 配列が必要な理由は、File.ReadAllLines
メソッドがデータを配列として返すためです。char
データ型が必要な理由は、Split
メソッドがarray
を返し、その各要素がchar
型であるためです。 (配列の詳細については、「Razor 構文を使用した ASP.NET Web プログラミングの概要」を参照してください。)ブラウザーでページを実行します。 前の例で入力したデータが表示されます。
ヒント
Microsoft Excel コンマ区切りファイルからのデータの表示
Microsoft Excel を使用して、スプレッドシートに含まれるデータをコンマ区切りファイル (.csv ファイル) として保存できます。 これを行うと、ファイルは Excel 形式ではなくプレーンテキストで保存されます。 テキスト ファイル内ではスプレッドシートの各行が改行で区切られ、各データ項目はコンマで区切られます。 前の例で示したコードを使用して、コード内のデータ ファイルの名前を変更するだけで、Excel のコンマ区切りファイルを読み取ることができます。
ファイルの削除
Web サイトからファイルを削除するには、File.Delete
メソッドを使用できます。 この手順では、ファイルの名前がわかっている場合に、ユーザーが images フォルダーから画像 (.jpg ファイル) を削除できるようにする方法を示します。
Note
重要: 実稼働用の Web サイトでは、通常、データの変更を許可するユーザーを制限します。 メンバーシップを設定する方法と、ユーザーがサイトでタスクを実行することを承認する方法については、「ASP.NET Web ページ サイトへのセキュリティとメンバーシップの追加」を参照してください。
Web サイトで、images という名前のサブフォルダーを作成します。
1 つ以上の.jpg ファイルを images フォルダーにコピーします。
Web サイトのルートで、FileDelete.cshtml という名前の新しいファイルを作成します。
既存のコンテンツを次に置き換えます。
@{ bool deleteSuccess = false; var photoName = ""; if (IsPost) { photoName = Request["photoFileName"] + ".jpg"; var fullPath = Server.MapPath("~/images/" + photoName); if (File.Exists(fullPath)) { File.Delete(fullPath); deleteSuccess = true; } } } <!DOCTYPE html> <html> <head> <title>Delete a Photo</title> </head> <body> <h1>Delete a Photo from the Site</h1> <form name="deletePhoto" action="" method="post"> <p>File name of image to delete (without .jpg extension): <input name="photoFileName" type="text" value="" /> </p> <p><input type="submit" value="Submit" /></p> </form> @if(deleteSuccess) { <p> @photoName deleted! </p> } </body> </html>
このページには、ユーザーが画像ファイルの名前を入力できるフォームが含まれています。 .jpg ファイル名拡張子は入力されません。ファイル名をこのように制限することで、ユーザーがサイト上の任意のファイルを削除するのを防ぐことができます。
コードで、ユーザーが入力したファイル名を読み取り、完全なパスを構築します。 パスを作成するために、コードで現在の Web サイト パス (
Server.MapPath
メソッドによって返されたもの)、images フォルダー名、ユーザーが指定した名前、リテラル文字列としての ".jpg" を使用します。ファイルを削除するために、コードで
File.Delete
メソッドを呼び出し、先ほど作成した完全なパスを渡します。 マークアップの最後に、ファイルが削除されたことを示す確認メッセージがコードで表示されます。ブラウザーでページを実行します。
削除するファイルの名前を入力し、[Submit] をクリックします。 ファイルが削除された場合、ファイルの名前がページの下部に表示されます。
ユーザーがファイルをアップロードできるようにする
FileUpload
ヘルパーを使用して、ユーザーが Web サイトにファイルをアップロードできるようにします。 次の手順は、ユーザーが 1 つのファイルをアップロードできるようにする方法を示しています。
まだ追加していない場合は、「ASP.NET Web ページ サイトへのヘルパーのインストール」の説明に従って、ASP.NET Web ヘルパー ライブラリを Web サイトに追加します。
App_Data フォルダーに新しいフォルダーを作成し、UploadedFiles という名前を付けます。
ルートで、FileUpload.cshtml という名前の新しいファイルを作成します。
ページ内の既存のコンテンツを次のように置き換えます。
@using Microsoft.Web.Helpers; @{ var fileName = ""; if (IsPost) { var fileSavePath = ""; var uploadedFile = Request.Files[0]; fileName = Path.GetFileName(uploadedFile.FileName); fileSavePath = Server.MapPath("~/App_Data/UploadedFiles/" + fileName); uploadedFile.SaveAs(fileSavePath); } } <!DOCTYPE html> <html> <head> <title>FileUpload - Single-File Example</title> </head> <body> <h1>FileUpload - Single-File Example</h1> @FileUpload.GetHtml( initialNumberOfFiles:1, allowMoreFilesToBeAdded:false, includeFormTag:true, uploadText:"Upload") @if (IsPost) { <span>File uploaded!</span><br/> } </body> </html>
ページの本文部分では、
FileUpload
ヘルパーを使用して、おそらくよく知っているアップロード ボックスとボタンを作成します。FileUpload
ヘルパーに設定するプロパティは、ファイルをアップロードするための 1 つのボックスを指定し、送信ボタンを [Upload] と表示する必要があることを指定します。 (この記事の後半で、さらにボックスを追加します。)ユーザーが [Upload] をクリックしたら、ページの上部にあるコードでファイルを取得して保存します。 フォーム フィールドから値を取得するために通常使用する
Request
オブジェクトには、アップロードされた 1 つ以上のファイルを含むFiles
配列もあります。 配列内の特定の位置から個々のファイルを取得できます。たとえば、最初にアップロードされたファイルを取得するには、Request.Files[0]
を取得します。2 番目のファイルを取得するには、Request.Files[1]
を取得します。 (プログラミングでは、カウントは通常 0 から始まる点に注意してください。)アップロードしたファイルをフェッチするときは、それを操作できるように変数 (ここでは
uploadedFile
) に格納します。 アップロードしたファイルの名前を確認するには、そのFileName
プロパティを取得するだけです。 ただし、ユーザーがファイルをアップロードするとき、FileName
にはパス全体を含むユーザーの元の名前が含まれます。 次のようになります。C:\Users\Public\Sample.txt
ただし、そのパス情報すべては必要ありません。それはユーザーのコンピューター上のパスであり、サーバーに対するものではないためです。 必要なのは実際のファイル名 (Sample.txt) だけです。
Path.GetFileName
メソッドを次のように使用して、パスからファイルだけを取り出すことができます。Path.GetFileName(uploadedFile.FileName)
Path
オブジェクトは、パスの削除、パスの結合などを行うために使用できる、このようなメソッドが多数あるユーティリティです。アップロードしたファイルの名前を取得したら、アップロードしたファイルを Web サイトに保存する場所の新しいパスを作成できます。 この場合は、
Server.MapPath
、フォルダー名 (App_Data/UploadedFiles)、新しく取り出したファイル名を組み合わせて新しいパスを作成します。 アップロードしたファイルのSaveAs
メソッドを呼び出して、実際にファイルを保存できます。ブラウザーでページを実行します。
[Browse] をクリックし、アップロードするファイルを選択します。
[Browse] ボタンの横にあるテキスト ボックスには、パスとファイルの場所が含まれます。
アップロードをクリックします。
Web サイトで、プロジェクト フォルダーを右クリックし、[最新の情報に更新] をクリックします。
UploadedFiles フォルダーを開きます。 アップロードしたファイルがフォルダー内にあります。
ユーザーが複数のファイルをアップロードできるようにする
前の例では、ユーザーが 1 つのファイルをアップロードできるようにしました。 ただし、FileUpload
ヘルパーを使用すると、一度に複数のファイルをアップロードできます。 これは、一度に 1 つずつファイルをアップロードするのは面倒な、写真のアップロードなどのシナリオで便利です。 (写真のアップロードについては、「ASP.NET Web ページ サイトでのイメージの操作」を参照してください。) この例では、ユーザーが一度に 2 つアップロードできるようにする方法を示しますが、同じ手法を使用してそれ以上のアップロードを行うことができます。
「ASP.NET Web ページ サイトへのヘルパーのインストール」の中で説明されているように、(まだ行っていない場合は) ASP.NET Web ヘルパー ライブラリを Web サイトに追加します。
FileUploadMultiple.cshtml という名前の新しいページを作成します。
ページ内の既存のコンテンツを次のように置き換えます。
@using Microsoft.Web.Helpers; @{ var message = ""; if (IsPost) { var fileName = ""; var fileSavePath = ""; int numFiles = Request.Files.Count; int uploadedCount = 0; for(int i =0; i < numFiles; i++) { var uploadedFile = Request.Files[i]; if (uploadedFile.ContentLength > 0) { fileName = Path.GetFileName(uploadedFile.FileName); fileSavePath = Server.MapPath("~/App_Data/UploadedFiles/" + fileName); uploadedFile.SaveAs(fileSavePath); uploadedCount++; } } message = "File upload complete. Total files uploaded: " + uploadedCount.ToString(); } } <!DOCTYPE html> <html> <head><title>FileUpload - Multiple File Example</title></head> <body> <form id="myForm" method="post" enctype="multipart/form-data" action=""> <div> <h1>File Upload - Multiple-File Example</h1> @if (!IsPost) { @FileUpload.GetHtml( initialNumberOfFiles:2, allowMoreFilesToBeAdded:true, includeFormTag:true, addText:"Add another file", uploadText:"Upload") } <span>@message</span> </div> </form> </body> </html>
この例では、ユーザーが既定で 2 つのファイルをアップロードできるように、ページの本文で
FileUpload
ヘルパーが構成されています。allowMoreFilesToBeAdded
がtrue
に設定されているため、ヘルパーは、ユーザーがさらにアップロード ボックスを追加できるリンクをレンダリングします。ユーザーがアップロードしたファイルを処理するために、前の例で使用したのと同じ基本的な手法をコードで使用して、
Request.Files
からファイルを取得し、保存します。 (適切なファイル名とパスを取得するために必要なさまざまなものを含みます。) 今回のイノベーションは、ユーザーが複数のファイルをアップロードする可能性があり、その数がわからないことです。 調べるには、Request.Files.Count
を取得できます。この数値を手に入れると、
Request.Files
をループ処理し、各ファイルを順番にフェッチして保存できます。 コレクションを既知の回数だけループ処理する場合は、for
ループを次のように使用できます。for(int i =0; i < numFiles; i++) { var uploadedFile = Request.Files[i]; if (uploadedFile.ContentLength > 0) { fileName = Path.GetFileName(uploadedFile.FileName); // etc. }
変数
i
は、ゼロから設定した任意の上限まで増える一時的なカウンターです。 この場合、上限はファイルの数です。 ただし、ASP.NET のカウント シナリオで一般的なようにカウンターは 0 から始まるため、上限は実際にはファイル数より 1 小さくなります。 (3 つのファイルがアップロードされた場合、カウントは 0 から 2 までになります。)uploadedCount
変数には、正常にアップロードされて保存されたすべてのファイルが合計されます。 このコードは、必要なファイルをアップロードできない可能性を考慮しています。ブラウザーでページを実行します。 ブラウザーには、ページとその 2 つのアップロード ボックスが表示されます。
アップロードする 2 つのファイルを選択します。
[Add another file] をクリックします。 ページに新しいアップロード ボックスが表示されます。
アップロードをクリックします。
Web サイトで、プロジェクト フォルダーを右クリックし、[最新の情報に更新] をクリックします。
UploadedFiles フォルダーを開き、正常にアップロードされたファイルを確認します。