在 ASP.NET 网页 (Razor) 站点中使用文件

作者 Tom FitzMacken

本文介绍如何在 ASP.NET 网页 (Razor) 站点中读取、写入、追加、删除和上传文件。

注意

如果要上传图像并 (对其进行操作,例如,) 翻转或调整其大小,请参阅在 ASP.NET 网页网站中使用图像

你将了解的内容:

  • 如何创建文本文件并向其写入数据。
  • 如何将数据追加到现有文件。
  • 如何读取文件并从中显示。
  • 如何从网站中删除文件。
  • 如何让用户上传一个或多个文件。

以下是本文中介绍的 ASP.NET 编程功能:

  • 对象 File ,它提供了一种管理文件的方法。
  • 帮助 FileUpload 程序。
  • 对象 Path ,它提供可用于操作路径和文件名的方法。

本教程中使用的软件版本

  • ASP.NET 网页 (Razor) 2
  • WebMatrix 2

本教程还适用于 WebMatrix 3。

创建文本文件并向其写入数据

除了在网站中使用数据库外,还可以使用文件。 例如,可以使用文本文件作为存储站点数据的简单方法。 (用于存储数据的文本文件有时称为 平面文件。) 文本文件可以采用不同的格式,如 .txt.xml.csv (逗号分隔值) 。

如果要将数据存储在文本文件中,可以使用 File.WriteAllText 方法指定要创建的文件和要写入到其中的数据。 在此过程中,你将创建一个页面,其中包含一个包含三 input 个元素的简单窗体, (名字、姓氏和电子邮件地址) 和一个 “提交 ”按钮。 当用户提交表单时,你将将用户的输入存储在文本文件中。

  1. 创建名为 App_Data 的新文件夹(如果尚不存在)。

  2. 在网站的根目录中,创建一个名为 UserData.cshtml 的新文件。

  3. 将现有内容替换为以下内容:

    @{
        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 标记创建包含三个文本框的窗体。 在代码中,使用 IsPost 属性确定页面是否已在开始处理之前提交。

    第一个任务是获取用户输入并将其分配给变量。 然后,代码将单独变量的值串联成一个逗号分隔的字符串,然后存储在不同的变量中。 请注意,逗号分隔符是包含在引号 (“,”) 中的字符串,因为从字面上将逗号嵌入到要创建的大字符串中。 在连接在一起的数据末尾,添加 Environment.NewLine。 这会 (换行符) 添加换行符。 使用所有这些串联创建的是如下所示的字符串:

    David,Jones,davidj@contoso.com
    

    (末尾有一个不可见的换行符。)

    然后, (dataFile) 创建一个变量,其中包含要在其中存储数据的文件的位置和名称。 设置位置需要一些特殊处理。 在网站中,在代码中引用绝对路径(如 web 服务器上的文件的 C:\Folder\File.txt )是一种错误的做法。 如果网站被移动,绝对路径将出错。 此外,对于托管站点, (而不是在自己的计算机上) 在编写代码时,您通常甚至不知道正确的路径是什么。

    但有时 (现在这样,若要编写文件) 需要一个完整的路径。 解决方法是使用 MapPath 对象的 方法 Server 。 这会返回网站的完整路径。 若要获取网站根路径,请 (使用 ~ 运算符将站点的虚拟根) 重新配置为 MapPath。 (还可以将子文件夹名称(如 ~/App_Data/)传递给该子文件夹,以获取该子文件夹的路径。) 然后,可以将其他信息连接到该方法返回的任何内容,以便创建完整路径。 在此示例中,将添加一个文件名。 (有关如何使用文件和文件夹路径的详细信息,请参阅使用 Razor 语法 ASP.NET 网页编程简介.)

    该文件保存在 App_Data 文件夹中。 此文件夹是 ASP.NET 中用于存储数据文件的特殊文件夹,如在 ASP.NET 网页站点中使用数据库简介中所述。

    WriteAllText对象的 方法File将数据写入文件。 此方法采用两个参数:名称 (,其中包含要写入的文件的路径) ,以及要写入的实际数据。 请注意,第一个 @ 参数的名称以字符作为前缀。 这告诉 ASP.NET 提供逐字字符串文本,不应以特殊方式解释“/”等字符。 (有关详细信息,请参阅 使用 Razor 语法 ASP.NET Web 编程简介。)

    注意

    为了使代码将文件保存在 App_Data 文件夹中,应用程序需要该文件夹的读写权限。 在开发计算机上,这通常不是问题。 但是,将站点发布到托管提供程序的 Web 服务器时,可能需要显式设置这些权限。 如果在托管提供程序的服务器上运行此代码并收到错误,检查托管提供程序以了解如何设置这些权限。

  • 在浏览器中运行页面。

    浏览器窗口的屏幕截图,其中显示了“名字”、“姓氏”和“Email”文本字段,其后跟有“提交”按钮。

  • 在字段中输入值,然后单击“ 提交”。

  • 关闭浏览器。

  • 返回到项目并刷新视图。

  • 打开 data.txt 文件。 在表单中提交的数据位于 文件中。

    数据点 t x t 文件的屏幕截图,其中显示了输入 Web 浏览器字段的数据已记录到 t x t 文件中。

  • 关闭 data.txt 文件。

将数据追加到现有文件

在上一个示例中,你用于 WriteAllText 创建一个文本文件,该文件中只有一段数据。 如果再次调用 方法并向其传递相同的文件名,则会完全覆盖现有文件。 但是,创建文件后,通常需要将新数据添加到文件末尾。 可以使用 对象的 方法File执行此操作AppendAllText

  1. 在网站中,创建 UserData.cshtml 文件的副本,并将副本命名为 UserDataMultiple.cshtml

  2. 将开始 <!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.";
        }
    }
    

    此代码具有与上一个示例中的一个更改。 它不使用 WriteAllText,而是使用 the AppendAllText 方法。 方法类似,只是 AppendAllText 将数据添加到文件末尾。 与 一 WriteAllText样, AppendAllText 如果文件尚不存在,则创建该文件。

  3. 在浏览器中运行页面。

  4. 输入字段的值,然后单击“ 提交”。

  5. 添加更多数据并再次提交表单。

  6. 返回到项目,右键单击项目文件夹,然后单击“ 刷新”。

  7. 打开 data.txt 文件。 它现在包含刚输入的新数据。

    数据点 t x t 文件的屏幕截图,其中显示了已记录在 Web 浏览器字段中输入的数据,但未覆盖以前的数据。

从文件读取和显示数据

即使不需要将数据写入文本文件,有时也可能需要从其中读取数据。 为此,可以再次使用 File 对象。 可以使用 File 对象单独读取每一行 (用换行符分隔) 或读取单个项,无论它们如何分隔。

此过程演示如何读取和显示在上一示例中创建的数据。

  1. 在网站的根目录中,创建一个名为 DisplayData.cshtml 的新文件。

  2. 将现有内容替换为以下内容:

    @{
        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 方法确定文件是否可用。 该代码还会检查文件是否为空。

    页面正文包含两个 foreach 循环,一个嵌套在另一个循环中。 外部 foreach 循环一次从数据文件获取一行。 在这种情况下,这些行由文件中的换行符定义 ,即每个数据项都位于其自己的行上。 外部循环在有序列表 (<li> 元素) 内创建新项 (<ol> 元素) 。

    内部循环使用逗号作为分隔符) ,将每个数据行拆分为字段 (项。 (根据上一个示例,这意味着每行包含三个字段 - 名字、姓氏和电子邮件地址,每个字段用逗号分隔。) 内部循环还会创建一个 <ul> 列表,并为数据行中的每个字段显示一个列表项。

    该代码演示了如何使用两种数据类型:数组和 char 数据类型。 数组是必需的, File.ReadAllLines 因为 方法以数组的形式返回数据。 数据类型 char 是必需的, Split 因为 方法返回 , array 其中每个元素的类型均为 char。 (有关数组的信息,请参阅 使用 Razor 语法 ASP.NET Web 编程简介。)

  3. 在浏览器中运行页面。 将显示为上述示例输入的数据。

    浏览器窗口的屏幕截图,其中显示了数组中显示的数据点 t x t 文件中的数据。

提示

显示 Microsoft Excel Comma-Delimited 文件中的数据

可以使用 Microsoft Excel 将电子表格中包含的数据保存为逗号分隔的文件 (.csv 文件) 。 执行此操作时,该文件以纯文本保存,而不是以 Excel 格式保存。 电子表格中的每一行由文本文件中的换行符分隔,每个数据项用逗号分隔。 只需更改代码中的数据文件的名称,即可使用上一示例中所示的代码读取 Excel 逗号分隔的文件。

删除文件

若要从网站中删除文件,可以使用 File.Delete 方法。 此过程演示如何让用户删除图像 (.jpg文件) (如果用户知道文件名)。

注意

重要 在生产网站中,通常限制允许对数据进行更改的人员。 有关如何设置成员身份以及如何授权用户在网站上执行任务的信息,请参阅向 ASP.NET 网页网站添加安全性和成员身份

  1. 在网站中创建名为 images 的子文件夹。

  2. 将一个或多个 .jpg 文件复制到 images 文件夹中。

  3. 在网站的根目录中,创建一个名为 FileDelete.cshtml 的新文件。

  4. 将现有内容替换为以下内容:

    @{
        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 文件扩展名;通过像这样限制文件名,有助于防止用户删除网站上的任意文件。

    该代码读取用户已输入的文件名,然后构造完整路径。 为了创建路径,代码使用方法) 返回 Server.MapPath 的当前网站路径 (、 图像 文件夹名称、用户提供的名称以及“.jpg”作为文本字符串。

    为了删除文件,代码会调用 File.Delete 方法,并向其传递刚刚构造的完整路径。 在标记末尾,代码显示一条确认消息,指出文件已删除。

  5. 在浏览器中运行页面。

    浏览器窗口的屏幕截图,其中显示了“从网站中删除照片”页面,其中包含文件名字段和“提交”按钮。

  6. 输入要删除的文件的名称,然后单击“ 提交”。 如果文件已删除,则文件的名称将显示在页面底部。

允许用户上传文件

帮助 FileUpload 程序允许用户将文件上传到网站。 下面的过程演示如何让用户上传单个文件。

  1. 如在 ASP.NET 网页网站中安装帮助程序中所述,将 ASP.NET Web 帮助程序库添加到网站(如果之前未添加)。

  2. App_Data 文件夹中,创建一个新的文件夹,并将其命名为 UploadedFiles

  3. 在根目录中,创建名为 FileUpload.cshtml 的新文件。

  4. 将页面中的现有内容替换为以下内容:

    @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 帮助程序创建你可能熟悉的上传框和按钮:

    “文件上传”Web 浏览器页面的屏幕截图,其中显示了“文件上传帮助程序文件选取器”和“上传”按钮。

    FileUpload 帮助程序设置的属性指定希望上传文件的单个框,并且希望“提交”按钮读取 “上传”。 (稍后将在文章中添加更多框。)

    当用户单击“ 上传”时,页面顶部的代码将获取并保存文件。 Request通常用于从窗体字段获取值的 对象还具有一个Files数组,其中包含已上传的文件 (或) 。 你可以从数组中的特定位置获取单个文件,例如,要获取第一个上传的文件,则获取 Request.Files[0]、获取第二个文件、获取 Request.Files[1],等等。 (请记住,在编程中,计数通常从零开始。)

    提取上传的文件时,将其放在此处 (变量中, uploadedFile) 以便可以对其进行操作。 若要确定上传的文件的名称,只需获取其 FileName 属性。 但是,当用户上传文件时, FileName 会包含用户的原始名称,其中包括整个路径。 它可能如下所示:

    C:\Users\Public\Sample.txt

    不过,你不需要所有这些路径信息,因为这是用户计算机上的路径,而不是服务器的路径。 只需将实际文件名 (Sample.txt) 。 可以使用 方法仅从路径 Path.GetFileName 中去除文件,如下所示:

    Path.GetFileName(uploadedFile.FileName)
    

    对象 Path 是一个实用工具,其中包含许多方法,可用于条带路径、组合路径等。

    获取上传文件的名称后,可以生成一个新路径,以便在网站中存储上传的文件。 在本例中,将 、文件夹名称 (App_Data/UploadedFiles) 和新剥离的文件名组合Server.MapPath在一起以创建新路径。 然后,可以调用上传文件的 SaveAs 方法来实际保存该文件。

  5. 在浏览器中运行页面。

    “文件上传单个文件示例”Web 浏览器页面的屏幕截图,其中显示了文件选取器和“上传”按钮。

  6. 单击“ 浏览 ”,然后选择要上传的文件。

    文件资源管理器窗口的屏幕截图,其中显示了以蓝色突出显示的文件和蓝色矩形中突出显示的“打开”按钮。

    浏览 ”按钮旁边的文本框将包含路径和文件位置。

    “文件上传单个文件示例”Web 浏览器页面的屏幕截图,其中显示了包含所选文件和“上传”按钮的文件选取器。

  7. 单击“上载” 。

  8. 在网站中,右键单击项目文件夹,然后单击“ 刷新”。

  9. 打开 UploadedFiles 文件夹。 上传的文件位于 文件夹中。

    项目文件夹层次结构的屏幕截图,其中显示了“上传的文件”文件夹内以蓝色突出显示的“示例”点 t x t 文件。

允许用户上传多个文件

在上一个示例中,你允许用户上传一个文件。 但你可以使用 FileUpload 帮助程序一次上传多个文件。 这对于上传照片等场景很方便,其中一次上传一个文件很繁琐。 (你可以阅读有关在 ASP.NET 网页网站中使用图像中上传照片的信息。) 此示例演示如何允许用户一次上传两个,尽管你可以使用相同的技术上传更多内容。

  1. 如在 ASP.NET 网页网站中安装帮助程序中所述,将 ASP.NET Web 帮助程序库添加到网站(如果尚未添加)。

  2. 创建名为 FileUploadMultiple.cshtml 的新页面。

  3. 将页面中的现有内容替换为以下内容:

    @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>
    

    在此示例中, FileUpload 页面正文中的帮助程序配置为允许用户默认上传两个文件。 因为 allowMoreFilesToBeAdded 设置为 true,帮助程序会呈现一个链接,允许用户添加更多上传框:

    文件上传多个文件示例 Web 浏览器页面的屏幕截图,其中显示了两个文件选取器和一个“上传”按钮。

    为了处理用户上传的文件,代码使用在上一示例中所用的相同基本技术 - 从 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 到 2.)

    变量 uploadedCount 包含成功上传和保存的所有文件的总和。 此代码考虑了无法上传预期文件的可能性。

  4. 在浏览器中运行页面。 浏览器显示页面及其两个上传框。

  5. 选择要上传的两个文件。

  6. 单击“ 添加另一个文件”。 该页显示一个新的上传框。

    “文件上传多个文件示例”Web 浏览器页面的屏幕截图,其中显示了两个包含所选文件和“上传”按钮的文件选取器。

  7. 单击“上载” 。

  8. 在网站中,右键单击项目文件夹,然后单击“ 刷新”。

  9. 打开 UploadedFiles 文件夹以查看已成功上传的文件。

其他资源

在 ASP.NET 网页网站中使用图像

导出到 CSV 文件