web-dev-qa-db-fra.com

Créer un fichier texte et télécharger

J'essaie d'écrire dans un fichier texte en mémoire, puis de télécharger ce fichier sans l'enregistrer sur le disque dur. J'utilise la StringWriter pour écrire le contenu:

StringWriter oStringWriter = new StringWriter();
oStringWriter.Write("This is the content");

Comment puis-je télécharger ce fichier?

EDIT: C’est la combinaison de réponses qui m’a donné ma solution. C'est ici:

StringWriter oStringWriter = new StringWriter();
oStringWriter.WriteLine("Line 1");
Response.ContentType = "text/plain";

Response.AddHeader("content-disposition", "attachment;filename=" + string.Format("members-{0}.csv",string.Format("{0:ddMMyyyy}",DateTime.Today)));
Response.Clear();

using (StreamWriter writer = new StreamWriter(Response.OutputStream, Encoding.UTF8))
{
    writer.Write(oStringWriter.ToString());
}
Response.End();
25
higgsy

Au lieu de stocker les données en mémoire, puis de les envoyer au flux de réponses, vous pouvez les écrire directement dans le flux de réponses:

using (StreamWriter writer = new StreamWriter(Response.OutputStream, Encoding.UTF8)) {
  writer.Write("This is the content");
}

L'exemple utilise le codage UTF-8, vous devriez le changer si vous utilisez un autre codage.

14
Guffa

Cela a résolu pour moi:

        MemoryStream ms = new MemoryStream();
        TextWriter tw = new StreamWriter(ms);
        tw.WriteLine("Line 1");
        tw.WriteLine("Line 2");
        tw.WriteLine("Line 3");
        tw.Flush();
        byte[] bytes = ms.ToArray();
        ms.Close();

        Response.Clear();
        Response.ContentType = "application/force-download";
        Response.AddHeader("content-disposition", "attachment;    filename=file.txt");
        Response.BinaryWrite(bytes);
        Response.End();     
17
VINICIUS SIN

Fondamentalement, vous créez un HttpHandler en implémentant l'interface IHttpHandler . Dans la méthode ProcessRequest, vous écrivez simplement votre texte dans context.Response. Vous devez également ajouter un en-tête Content-Disposition http:

context.Response.AddHeader("Content-Disposition", "attachment; filename=YourFileName.txt");

Pensez également à définir la ContentType:

context.Response.ContentType = "text/plain";
5

Juste un petit ajout aux autres réponses. A la toute fin d'un téléchargement, j'exécute:

context.Response.Flush();
context.ApplicationInstance.CompleteRequest();

J'ai appris que sinon, le téléchargement ne se termine parfois pas correctement. 

Cet article de Google Groupes indique également que Response.End génère une variable ThreadAbortException que vous pouvez éviter en utilisant la méthode CompleteRequest.

2
Uwe Keim

J'ai eu beaucoup de problèmes avec cela. Finnaly a trouvé une solution qui semble fonctionner à chaque fois.

Dans la plupart des cas, l'utilisateur va cliquer sur un bouton pour le téléchargement. À ce stade, il est préférable de rediriger la page au même endroit. ajoutez un paramètre dans l'URL que vous pouvez saisir et lire. 

exemple (www.somewhere.com/mypage.aspx?print=stuff)

    <asp:Button ID="btn" runat="server" Text="print something" OnClick="btn_Click" />


    protected void Page_Load(object sender, EventArgs e) {
        if (Request["print"] == "stuff") { Print("my test content"); }
    }

    /* or pass byte[] content*/
    private void Print(string content ){ 
        Response.ContentType = "text/plain";
        Response.AddHeader("content-disposition", "attachment;filename=myFile.txt");
        // Response.BinaryWrite(content);
        Response.Write(content);
        Response.Flush(); 
        Response.End();
    }

    protected void btn_Click(object sender, EventArgs e) {
        // postbacks give you troubles if using async.
        // Will give an error when Response.End() is called.
        Response.Redirect(Request.Url + "?print=queue");
    }
0
Mike

Extension de la réponse @Vinicious.

J'ai eu des données qui pourraient contenir des virgules. La solution courante consiste à échapper à cette donnée en la mettant entre guillemets, tout en veillant à échapper également à des citations qui pourraient également faire partie des données.

Un frottement contre lequel je suis venu et un avertissement lors de la rédaction de fichiers CSV, Excel ne vous plaira pas si vous mettez des espaces à la suite des virgules. solution découverte à mon problème de la part du superutilisateur

protected void btnDownload_Click(object sender, EventArgs e)
{
    MemoryStream ms = new MemoryStream();
    TextWriter tw = new StreamWriter(ms, System.Text.Encoding.UTF8);
    var structures = KAWSLib.BusinessLayer.Structure.GetStructuresInService();
    // *** comma delimited
    tw.Write("Latitude, Longitude, CountySerial, StructureType, Orientation, District, RoutePre, RouteNo, LocationDesc");
    foreach (var s in structures)
    {
        tw.Write(Environment.NewLine + string.Format("{0:#.000000},{1:#.000000},{2},{3},{4},{5},{6},{7},{8}", s.LATITUDE, s.LONGITUDE, s.CO_SER, EscapeIfNeeded(s.SuperTypeLookup.SHORTDESC), EscapeIfNeeded(s.OrientationLookup.SHORTDESC), s.DISTRICT, s.ROUTE_PREFIX, s.RouteValue, EscapeIfNeeded(s.LOC_DESC)));
    }
    tw.Flush();
    byte[] bytes = ms.ToArray();
    ms.Close();

    Response.Clear();
    Response.ContentType = "application/force-download";
    Response.AddHeader("content-disposition", "attachment;    filename=" + string.Format("kaws-structures-{0:yyyy.MM.dd}.csv", DateTime.Today));
    Response.BinaryWrite(bytes);
    Response.End();
}

string EscapeIfNeeded(string s)
{
    if (s.Contains(","))
    {
        return "\"" + s.Replace("\"", "\"\"") + "\"";
    }
    else
    {
        return s;
    }
}

Ci-dessous entraînera un problème pour Excel. Dans Excel, le premier devis fera partie des données et, par conséquent, sera séparé à la virgule intégrée. Les espaces sont mauvais.

 tw.Write(Environment.NewLine + string.Format("{0:#.000000}, {1:#.000000}, {2}, {3}, {4}, {5}, {6}, {7}, {8}", s.LATITUDE, s.LONGITUDE, s.CO_SER, EscapeIfNeeded(s.SuperTypeLookup.SHORTDESC), EscapeIfNeeded(s.OrientationLookup.SHORTDESC), s.DISTRICT, s.ROUTE_PREFIX, s.RouteValue, EscapeIfNeeded(s.LOC_DESC)));
0
eric1825