我有一个用流初始化的StreamReader对象,现在我想将这个流保存到磁盘(流可以是.gif、.jpg或.pdf)。
现有代码:
StreamReader sr = new StreamReader(myOtherObject.InputStream);
我需要将其保存到磁盘(我有文件名)。将来我可能希望将其存储到SQL Server。
我还有编码类型,如果我将其存储到SQL Server,我将需要它,对吗?
我有一个用流初始化的StreamReader对象,现在我想将这个流保存到磁盘(流可以是.gif、.jpg或.pdf)。
现有代码:
StreamReader sr = new StreamReader(myOtherObject.InputStream);
我需要将其保存到磁盘(我有文件名)。将来我可能希望将其存储到SQL Server。
我还有编码类型,如果我将其存储到SQL Server,我将需要它,对吗?
当前回答
您不能将StreamReader用于二进制文件(如gifs或jpgs)。StreamReader用于文本数据。如果将其用于任意二进制数据,几乎肯定会丢失数据。(如果您使用Encoding.GetEncoding(28591),您可能会没事,但有什么意义?)
为什么您需要使用StreamReader?为什么不将二进制数据保留为二进制数据,并将其作为二进制数据写回磁盘(或SQL)?
编辑:因为这似乎是人们想要看到的。。。如果您只想将一个流复制到另一个流(例如,复制到文件),请使用以下操作:
/// <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);
}
}
要使用它将流转储到文件,例如:
using (Stream file = File.Create(filename))
{
CopyStream(input, file);
}
请注意,Stream.CopyTo是在.NET4中引入的,其目的基本相同。
其他回答
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);
}
}
}
//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.
*/
另一个选项是将流设置为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.
}
public void CopyStream(Stream stream, string destPath)
{
using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write))
{
stream.CopyTo(fileStream);
}
}
下面是一个使用idispable的正确用法和实现的示例:
static void WriteToFile(string sourceFile, string destinationfile, bool append = true, int bufferSize = 4096)
{
using (var sourceFileStream = new FileStream(sourceFile, FileMode.OpenOrCreate))
{
using (var destinationFileStream = new FileStream(destinationfile, FileMode.OpenOrCreate))
{
while (sourceFileStream.Position < sourceFileStream.Length)
{
destinationFileStream.WriteByte((byte)sourceFileStream.ReadByte());
}
}
}
}
…还有这个
public static void WriteToFile(Stream stream, string destinationFile, int bufferSize = 4096, FileMode mode = FileMode.OpenOrCreate, FileAccess access = FileAccess.ReadWrite, FileShare share = FileShare.ReadWrite)
{
using (var destinationFileStream = new FileStream(destinationFile, mode, access, share))
{
while (stream.Position < stream.Length)
{
destinationFileStream.WriteByte((byte)stream.ReadByte());
}
}
}
关键是理解using的正确用法(应该在实现idisposable的对象的实例化中实现,如上图所示),并对流的财产是如何工作的有一个好主意。Position实际上是流中的索引(从0开始),当使用readbyte方法读取每个字节时,该索引跟随其后。在这种情况下,我本质上是用它来代替for循环变量,并简单地让它一直跟随到整个流的长度(以字节为单位)。忽略字节,因为它实际上是相同的,您将得到像这样简单而优雅的东西,可以干净地解决所有问题。
还请记住,ReadByte方法只需在过程中将字节强制转换为int,并可以简单地转换回。
我将添加我最近编写的另一个实现,以创建一个动态缓冲区,以确保连续的数据写入,防止大量过载
private void StreamBuffer(Stream stream, int buffer)
{
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
var memoryBuffer = memoryStream.GetBuffer();
for (int i = 0; i < memoryBuffer.Length;)
{
var networkBuffer = new byte[buffer];
for (int j = 0; j < networkBuffer.Length && i < memoryBuffer.Length; j++)
{
networkBuffer[j] = memoryBuffer[i];
i++;
}
//Assuming destination file
destinationFileStream.Write(networkBuffer, 0, networkBuffer.Length);
}
}
}
解释很简单:我们知道我们需要记住我们希望写入的整个数据集,而且我们只想写入特定的数据量,所以我们希望第一个循环的最后一个参数为空(与while相同)。接下来,我们初始化一个字节数组缓冲区,该缓冲区设置为传递的大小,在第二个循环中,我们将j与缓冲区大小和原始缓冲区大小进行比较,如果它大于原始字节数组的大小,则结束运行。