Как правильно обслуживать PDF-файл - PullRequest
3 голосов
/ 31 января 2010

Я использую .NET 3.5 ASP.NET. В настоящее время мой веб-сайт обслуживает PDF-файл следующим образом:

context.Response.WriteFile(@"c:\blah\blah.pdf");

Это прекрасно работает. Тем не менее, я хотел бы обслужить его методом context.Response.Write(char [], int, int).

Итак, я попытался отправить файл через

byte [] byteContent = File.ReadAllBytes(ReportPath);
ASCIIEncoding encoding = new ASCIIEncoding();
char[] charContent = encoding.GetChars(byteContent);
context.Response.Write(charContent, 0, charContent.Length);

Это не сработало (например, плагин браузера PDF жалуется, что файл поврежден).

Итак, я попробовал подход Unicode:

byte [] byteContent = File.ReadAllBytes(ReportPath);
UnicodeEncoding encoding = new UnicodeEncoding();
char[] charContent = encoding.GetChars(byteContent);
context.Response.Write(charContent, 0, charContent.Length);

, который также не работал.

Что мне не хватает?

Ответы [ 3 ]

7 голосов
/ 31 января 2010

Не следует конвертировать байты в символы, поэтому он становится «поврежденным».Даже если символы ASCII хранятся в байтах, фактический набор символов ASCII ограничен 7 битами.Таким образом, преобразование потока байтов с помощью ASCIIEncoding эффективно удалит 8-й бит из каждого байта.

Байты должны быть записаны в поток OutputStream экземпляра Response.

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

void LoadStreamToStream(Stream inputStream, Stream outputStream)
{
    const int bufferSize = 64 * 1024;
    var buffer = new byte[bufferSize];

    while (true)
    {
        var bytesRead = inputStream.Read(buffer, 0, bufferSize);
        if (bytesRead > 0)
        {
            outputStream.Write(buffer, 0, bytesRead);
        }
        if ((bytesRead == 0) || (bytesRead < bufferSize))
            break;
    }
}

Затем вы можете использовать этот метод для загрузки содержимого вашего файла непосредственно в Response.OutputStream

LoadStreamToStream(fileStream, Response.OutputStream);

Еще лучше, вот метод, открывающий файл и загружающий его содержимое в поток:

void LoadFileToStream(string inputFile, Stream outputStream)
{
    using (var streamInput = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    {
        LoadStreamToStream(streamInput, outputStream);
        streamInput.Close();
    }
}
2 голосов
/ 31 января 2010

Вам также может понадобиться установить ContentType, выполнив что-то вроде этого:

Response.ContentType = "application/octet-stream";
0 голосов
/ 17 февраля 2016

Опираясь на ответ Питера Лиллевольда , я пошел и просто сделал несколько методов расширения для его вышеупомянутых функций.

public static void WriteTo(this Stream inputStream, Stream outputStream)
{
    const int bufferSize = 64 * 1024;
    var buffer = new byte[bufferSize];

    while (true)
    {
        var bytesRead = inputStream.Read(buffer, 0, bufferSize);
        if (bytesRead > 0)
        {
            outputStream.Write(buffer, 0, bytesRead);
        }
        if ((bytesRead == 0) || (bytesRead < bufferSize)) break;
    }
}

public static void WriteToFromFile(this Stream outputStream, string inputFile)
{
    using (var inputStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    {
        inputStream.WriteTo(outputStream);
        inputStream.Close();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...