如何将stream保存到C#文件中?

我有一个StreamReader对象,我初始化一个stream,现在我想保存这个stream到磁盘(该stream可能是.gif.jpg.pdf )。

现有代码:

 StreamReader sr = new StreamReader(myOtherObject.InputStream); 
  1. 我需要将其保存到磁盘(我有文件名)。
  2. 将来,我可能希望将其存储到SQL Server。

我也有编码types,如果我将它存储到SQL Server,我将需要正确的?

正如Jon Skeet的回答中的Tilendor所强调的,从.NET 4开始,stream有一个CopyTo方法。

 var fileStream = File.Create("C:\\Path\\To\\File"); myOtherObject.InputStream.Seek(0, SeekOrigin.Begin); myOtherObject.InputStream.CopyTo(fileStream); fileStream.Close(); 

或者using语法:

 using (var fileStream = File.Create("C:\\Path\\To\\File")) { myOtherObject.InputStream.Seek(0, SeekOrigin.Begin); myOtherObject.InputStream.CopyTo(fileStream); } 

不能StreamReader用于二进制文件(如gif或jpgs)。 StreamReader用于文本数据。 如果您将其用于任意二进制数据,您肯定会丢失数据。 (如果你使用Encoding.GetEncoding(28591),你可能会好起来,但是有什么意义呢?)

为什么你需要使用StreamReader呢? 为什么不把二进制数据保存二进制数据,并将其作为二进制数据写回磁盘(或SQL)?

编辑:因为这似乎是人们想看到的东西…如果你只是想复制一个stream到另一个(例如到一个文件)使用这样的东西:

 /// <summary> /// Copies the contents of input to output. Doesn't close either stream. /// </summary> public static void CopyStream(Stream input, Stream output) { byte[] buffer = new byte[8 * 1024]; int len; while ( (len = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, len); } } 

要使用它来将stream转储到文件,例如:

 using (Stream file = File.Create(filename)) { CopyStream(input, file); } 

请注意, Stream.CopyTo是在.NET 4中引入的,它的用途基本相同。

 public void CopyStream(Stream stream, string destPath) { using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write)) { stream.CopyTo(fileStream); } } 
 private void SaveFileStream(String path, Stream stream) { var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write); stream.CopyTo(fileStream); fileStream.Dispose(); } 
 //If you don't have .Net 4.0 :) public void SaveStreamToFile(Stream stream, string filename) { using(Stream destination = File.Create(filename)) Write(stream, destination); } //Typically I implement this Write method as a Stream extension method. //The framework handles buffering. public void Write(Stream from, Stream to) { for(int a = from.ReadByte(); a != -1; a = from.ReadByte()) to.WriteByte( (byte) a ); } /* Note, StreamReader is an IEnumerable<Char> while Stream is an IEnumbable<byte>. The distinction is significant such as in multiple byte character encodings like Unicode used in .Net where Char is one or more bytes (byte[n]). Also, the resulting translation from IEnumerable<byte> to IEnumerable<Char> can loose bytes or insert them (for example, "\n" vs. "\r\n") depending on the StreamReader instance CurrentEncoding. */ 

为什么不使用FileStream对象?

 public void SaveStreamToFile(string fileFullPath, Stream stream) { if (stream.Length == 0) return; // Create a FileStream object to write a stream to a file using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length)) { // Fill the bytes[] array with the stream data byte[] bytesInStream = new byte[stream.Length]; stream.Read(bytesInStream, 0, (int)bytesInStream.Length); // Use FileStream object to write to the specified file fileStream.Write(bytesInStream, 0, bytesInStream.Length); } } 
 public void testdownload(stream input) { byte[] buffer = new byte[16345]; using (FileStream fs = new FileStream(this.FullLocalFilePath, FileMode.Create, FileAccess.Write, FileShare.None)) { int read; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { fs.Write(buffer, 0, read); } } } 

我没有得到使用CopyTo所有答案,其中使用该应用程序的系统可能没有升级到.NET 4.0+。 我知道有些想强迫人升级,但兼容性也不错。

另一件事,我没有使用一个stream从第一个地方复制从另一个stream。 为什么不只是做:

 byte[] bytes = myOtherObject.InputStream.ToArray(); 

一旦你有字节,你可以很容易地把它们写到一个文件中:

 public static void WriteFile(string fileName, byte[] bytes) { string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!path.EndsWith(@"\")) path += @"\"; if (File.Exists(Path.Combine(path, fileName))) File.Delete(Path.Combine(path, fileName)); using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write) { fs.Write(bytes, 0, (int)bytes.Length); fs.Close(); } } 

这段代码的工作原理是用.jpg文件testing过的,尽pipe我承认我只用它来处理小文件(小于1MB)。 一个stream,不在stream之间复制,不需要编码,只需写入字节! 如果您已经拥有了一个可以直接使用.ToArray()转换为bytes的数据stream,则无需使用StreamReader过度复杂化。

只有潜在的缺点,我可以看到这样做,如果有一个大文件,有一个stream,并使用.CopyTo()或等效允许FileStreamstream,而不是使用一个字节数组,并读取字节一。 这样做可能会比较慢,因此。 但是它不应该被扼杀,因为FileStream.Write()方法处理写入字节,并且一次只做一个字节,所以它不会阻塞内存,除了必须有足够的内存将stream保存为一个byte[]对象 。 在我使用这个的情况下,得到一个OracleBlob ,我不得不去一个byte[] ,这是足够小的,而且,有没有stream可用于我,无论如何,所以我只是发送我的字节到我的函数,以上。

另一个select,使用stream,将与另一篇文章中的Jon Skeet的CopyStream函数一起使用 – 这只是使用FileStream来获取inputstream,并直接创build文件。 它不像他那样使用File.Create (最初看起来对我来说是有问题的,但后来发现它可能只是一个VS bug)。

 /// <summary> /// Copies the contents of input to output. Doesn't close either stream. /// </summary> public static void CopyStream(Stream input, Stream output) { byte[] buffer = new byte[8 * 1024]; int len; while ( (len = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, len); } } public static void WriteFile(string fileName, Stream inputStream) { string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!path.EndsWith(@"\")) path += @"\"; if (File.Exists(Path.Combine(path, fileName))) File.Delete(Path.Combine(path, fileName)); using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write) { CopyStream(inputStream, fs); } inputStream.Close(); inputStream.Flush(); } 

另一种select是将stream传输到byte[]并使用File.WriteAllBytes 。 这应该做的:

 using (var stream = new MemoryStream()) { input.CopyTo(stream); File.WriteAllBytes(file, stream.ToArray()); } 

用扩展方法包装它可以给它更好的命名:

 public void WriteTo(this Stream input, string file) { //your fav write method: using (var stream = File.Create(file)) { input.CopyTo(stream); } //or using (var stream = new MemoryStream()) { input.CopyTo(stream); File.WriteAllBytes(file, stream.ToArray()); } //whatever that fits. }