我有一个StreamReader
用流初始化的对象,现在我想将此流保存到磁盘(流可以是.gif
或.jpg
或.pdf
).
现有守则:
StreamReader sr = new StreamReader(myOtherObject.InputStream);
我需要将其保存到磁盘(我有文件名).
在将来,我可能希望将其存储到SQL Server.
我也有编码类型,如果我将它存储到SQL Server,我将需要,对吗?
正如Tilendor在Jon Skeet的回答中强调的那样,CopyTo
自.NET 4以来,流有一种方法.
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
二进制文件(如gifs或jpgs).StreamReader
用于文本数据.如果将它用于任意二进制数据,几乎肯定会丢失数据.(如果你使用Encoding.GetEncoding(28591),你可能会没事,但重点是什么?)
为什么你需要使用一个StreamReader
?为什么不将二进制数据保存为二进制数据并将其作为二进制数据写回磁盘(或SQL)?
编辑:由于这似乎是人们想要的东西,看看......如果你不只是要一个流复制到另一个(如一个文件)使用是这样的:
////// Copies the contents of input to output. Doesn't close either stream. /// 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); } }
要使用它将流转储到文件,例如:
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(); }
我没有得到所有答案CopyTo
,可能使用该应用程序的系统可能尚未升级到.NET 4.0+.我知道有些人想强迫人们升级,但兼容性也很好.
另一件事,我没有首先使用流从另一个流复制.为什么不这样做:
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
文件对它进行了测试,但我承认我只使用了小文件(小于1 MB).一个流,流之间没有复制,不需要编码,只需写入字节!StreamReader
如果您已经拥有可以bytes
直接转换为的流,则无需过度复杂化.ToArray()
!
我只能通过这种方式看到的潜在缺点是,如果有一个大文件,将其作为流使用.CopyTo()
或使用或等效允许FileStream
流式传输而不是使用字节数组并逐个读取字节.结果这样做可能会慢一些.但它不应该因为句柄的.Write()
方法FileStream
写入字节而窒息,并且它一次只做一个字节,所以它不会阻塞内存,除了你必须有足够的内存来保存流作为一个byte[]
对象.在我使用它的情况下,获得一个OracleBlob
,我必须去一个byte[]
,它足够小,而且,无论如何,我没有可用的流,所以我只是把我的字节发送到我的函数,上面.
使用流的另一个选择是将它与Jon Skeet的CopyStream
功能一起使用,该功能位于另一个帖子中 - 这只是FileStream
用来获取输入流并直接从中创建文件.它没有File.Create
像他那样使用(最初对我来说似乎有问题,但后来发现它可能只是一个VS bug ......).
////// Copies the contents of input to output. Doesn't close either stream. /// 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(); }
//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 IEnumerablewhile Stream is an IEnumbable . 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 to IEnumerable 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); } }
另一个选择是将流转到a 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. }