如何正确地提供PDF文件
我使用的是.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);
这也没用。
我错过了什么?
您不应该将字节转换为字符,这就是它变为“损坏”的原因。 即使ASCII字符以字节存储,实际的ASCII字符集也限制为7位。 因此,使用ASCIIEncoding转换字节流将有效地从每个字节中删除第8位。
应将字节写入Response实例的OutputStream流。
而不是从文件中预先加载所有可能消耗大量内存的字节,从流中读取块中的文件是一种更好的方法。 这是一个如何从一个流读取然后写入另一个流的示例:
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(); } }
您可能还需要通过执行以下操作来设置ContentType:
Response.ContentType = "application/octet-stream";
在Peter Lillevold的回答的基础上,我去了,并为他的上述function做了一些扩展方法。
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(); } }