Система. Поточная обработка. Поток. CurrentThread. CurrentCulture
Вот метод, который я использую. Это возвращает вложение, поэтому IE создает диалоговое окно «Открыть / сохранить». Я также знаю, что файлы не будут больше 1M, поэтому я уверен, что есть более чистый способ сделать это.
У меня была аналогичная проблема с PDF-файлами, и я понял, что мне абсолютно необходимо использовать двоичные потоки и ReadBytes. Все, что связано со строками, испортило его.
Stream stream = GetStream(); // Assuming you have a method that does this.
BinaryReader reader = new BinaryReader(stream);
HttpResponse response = HttpContext.Current.Response;
response.ContentType = "application/pdf";
response.AddHeader("Content-Disposition", "attachment; filename=file.pdf");
response.ClearContent();
response.OutputStream.Write(reader.ReadBytes(1000000), 0, 1000000);
// End the response to prevent further work by the page processor.
response.End();
У меня есть нечто подобное, работающее над текущим веб-сайтом 2.0. И я помню, как пытался заставить его работать, хотя прошло какое-то время, поэтому я не помню, как это было.
Однако есть несколько отличий между тем, что у меня есть, что есть у вас. Надеюсь, это поможет вам решить проблему.
И еще одно:
Этот фрагмент сделал это за меня:
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = mimeType;
Response.AddHeader("Content-Disposition", "attachment");
Response.WriteFile(filePath);
Response.Flush();
Другие варианты копируют содержимое файла в память перед отправкой ответа. Если данные уже находятся в памяти, то у вас будет две копии, что не очень хорошо для масштабируемости. Вместо этого лучше использовать следующее:
public void SendFile(Stream inputStream, long contentLength, string mimeType, string fileName)
{
string clength = contentLength.ToString(CultureInfo.InvariantCulture);
HttpResponse response = HttpContext.Current.Response;
response.ContentType = mimeType;
response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
if (contentLength != -1) response.AddHeader("Content-Length", clength);
response.ClearContent();
inputStream.CopyTo(response.OutputStream);
response.OutputStream.Flush();
response.End();
}
Поскольку поток - это набор байтов, нет необходимости использовать BinaryReader. И пока входной поток заканчивается в конце файла, вы можете просто использовать метод CopyTo() для потока, который вы хотите отправить в веб-браузер. Все содержимое будет записано в целевой поток без создания каких-либо промежуточных копий данных.
Если вам нужно скопировать только определенное количество байт из потока, вы можете создать метод расширения, который добавит еще пару перегрузок CopyTo():
public static class Extensions
{
public static void CopyTo(this Stream inStream, Stream outStream, long length)
{
CopyTo(inStream, outStream, length, 4096);
}
public static void CopyTo(this Stream inStream, Stream outStream, long length, int blockSize)
{
byte[] buffer = new byte[blockSize];
long currentPosition = 0;
while (true)
{
int read = inStream.Read(buffer, 0, blockSize);
if (read == 0) break;
long cPosition = currentPosition + read;
if (cPosition > length) read = read - Convert.ToInt32(cPosition - length);
outStream.Write(buffer, 0, read);
currentPosition += read;
if (currentPosition >= length) break;
}
}
}
Затем вы можете использовать его следующим образом:
inputStream.CopyTo(response.OutputStream, contentLength);
Это будет работать с любым входным потоком, но в качестве примера можно привести чтение файла из файловой системы:
string filename = @"C:\dirs.txt";
using (FileStream fs = File.Open(filename, FileMode.Open))
{
SendFile(fs, fs.Length, "application/octet-stream", filename);
}
Как уже говорилось, убедитесь, что ваш MIME-тип соответствует содержимому.