пятница, 10 октября 2014 г.

Создаем .csv файлы в ASP.NET

Иногда возникает необходимость выгрузить какие-то данные в удобном для пользователя формате, который позволит на них не только смотреть, но и как-то обрабатывать и редактировать. Самым очевидным межплатформенным решением в таком случае видится форма CSV.

Выгрузить CSV-файл с нужными данными можно несколькими способами:
красивым и правильным, с использованием ASP.NET хэндлера (о хендлерах я как-нибудь напишу отдельно),
изврашенным - написав консольное приложение, которое будет запускаться по определенному графику и создавать где-нибудь доступный для web-сервера файл,
и простым и не очень правильным - просто изменив MIME-тип в ASPX-странице.
Какой бы способ вы не выбрали, все сведется примерно к такому коду:

 
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("1,2,3,4");
            sb.AppendLine("5,6,7,8");
            sb.AppendLine("9,10,11,12");
            Response.ClearContent();
            Response.Clear();
            Response.ContentEncoding = Encoding.GetEncoding("Windows-1251");
            Response.ContentType = "application/vnd.ms-excel";
            Response.AddHeader("Content-Disposition", "attachment; filename=csvfile.csv;");
            Response.Write(sb.ToString());
            Response.Flush();
            Response.End();

Если у вас операционная система Windows и установлена англоязычная локаль, то все будет работать и вы не узнаете что есть небольшая проблема до того момента, пока кто-то из пользователей вам об этом не сообщит.

А проблема вот в чем, если сменить локаль, например, на русскую или испанскую, то при открытии сгенерированного вами файла в Excel будет получаться вот такая ерунда:

Не знаю, как на других операционных системах и в других системах электронных таблиц, но Excel берет данные о разделителе элементов из настроек локали, посмотреть которые можно тут (это установки для русскоязычных настроек):

В ASP.NET единственное, что мы может узнать о локали пользователя - это ISO 639-1 строку, например "ru-RU". Это наводит на неприятные мысли либо о создании справочника разделителей для каждой строки локали или использования чего-нибудь типа OpenXML и создания полноценных .XLSX-файлов.

На самом деле, все значительно проще. Достаточно добавить в начало CSV-файла строку вида sep=<ваш разделитель>
например вот так:

 
            sb.AppendLine("sep=,");

и все. Теперь сгенерированный вами файл будет открываться корректно. И естественно, разделителем можно назначит не только запятую.

1 комментарий:

  1. Более короткий вариант:
    return File(Encoding.GetEncoding("Windows-1251").GetBytes(sb.ToString()), "text/csv", "Report123.csv");

    ОтветитьУдалить