c#如何发送仍在编写的文件流并一直发送到创建结束
我有一个Restful web服务,其中包含一个返回流的方法,调用此方法会在下载与流关联的文件时产生结果 现在,出于性能目的,我需要在创建该文件时下载该文件。 以下是该方法的实际代码:c#如何发送仍在编写的文件流并一直发送到创建结束,c#,rest,io,stream,download,C#,Rest,Io,Stream,Download,我有一个Restful web服务,其中包含一个返回流的方法,调用此方法会在下载与流关联的文件时产生结果 现在,出于性能目的,我需要在创建该文件时下载该文件。 以下是该方法的实际代码: [WebGet(UriTemplate = "SendFileStream/")] public Stream SendFileStream() { //This thread generates a big file FileCreatorThread f
[WebGet(UriTemplate = "SendFileStream/")]
public Stream SendFileStream()
{
//This thread generates a big file
FileCreatorThread fileCreator = new FileCreatorThread();
Thread fileCreatorThread = new Thread(fileCreator.CreateFile);
fileCreatorThread.Start();
WebOperationContext.Current.OutgoingResponse.Headers.Add(HttpResponseHeader.Expires, DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'"));
WebOperationContext.Current.OutgoingResponse.ContentType = "multipart/related";
FileStream fs = new FileStream(@"c:\test.txt", FileMode.Open, FileAccess.Read, FileShare.Write);
return fs;
}
此方法非常有效,文件在创建时可以下载,而不会引发IOException。
但问题是下载速度比创建速度快,并且在到达流的末尾时停止,而不下载仍然需要创建的部分
所以我的问题是,有没有办法让下载一直挂起,直到文件创建结束(假设我们事先不知道这个文件的最终长度)不需要第二种方法来检查下载文件的大小是否与实际文件的长度相同,是否需要一种方法来重新启动下载,直到下载完成
提前感谢你的帮助
PS:对于那些想知道如何使用两个不同线程以读写方式访问文件的人,下面是生成文件的线程的代码
public class FileCreatorThread
{
public void CreateFile()
{
FileStream fs = new FileStream(@"c:\test.txt", FileMode.Create, FileAccess.Write, FileShare.Read);
StreamWriter writer = new StreamWriter(fs);
for (int i = 0; i < 1000000; i++)
{
writer.WriteLine("New line number " + i);
writer.Flush();
//Thread.Sleep(1);
}
writer.Close();
fs.Close();
}
}
这可能不是更干净或最有效的方法,因此请毫不犹豫地发表评论并提出其他解决方案
更新2:
这里是Read()方法的一个更有效的版本,因为如果编写器写入更多字节所需的时间超过815毫秒,我第一次发布的方法仍然可能失败
public override int Read(byte[] buffer, int offset, int count)
{
int countRead = inStream.Read(buffer, offset, count);
if (countRead != 0)
{
return countRead;
}
else
{
Boolean fileAccessible = false;
while (!fileAccessible)
{
try
{
//try to open the file in Write, if it goes in exception, that means that the file is still opened by the writer
testStream = new FileStream(this.filePath, FileMode.Open, FileAccess.Write, FileShare.Read);
testStream.Close();
break;
}
catch (Exception e)
{
Thread.Sleep(500);
countRead = inStream.Read(buffer, offset, count);
if (countRead != 0)
{
return countRead;
}
}
}
countRead = inStream.Read(buffer, offset, count);
return countRead;
}
}
您遇到的问题是,您试图获取整个文件,而不是文件的一部分 当从一侧写入文件时,另一侧应同时请求一个段。假设每个周期4096字节,然后在片段达到文件长度时创建整个文件 我知道有一种方法可以使用WCF异步Web服务调用 试着朝这个方向解决你的问题
如果您仍然有问题,请与我联系。谢谢您的回答,我会朝这个方向看,如果我让它工作或卡住了,我会随时通知您。我最终解决了我的问题,但不是您所想的那样。我的解决方案分为两个步骤:1:在WCF服务中启用流传输2:使用自定义流实现,并重载读取方法,如果已到达文件结尾,则等待几毫秒并重试读取,以确保确实已到达文件结尾,我将使用解决方案更新我的问题。无论如何,我不确定这是否是最好的方法,如果你想改进,请毫不犹豫地告诉我。你能在这里发布你的解决方案吗?在这里,请告诉我你对它的看法。谢谢你的帮助,我接受答案,即使它不完全是,它引导我找到这个解决方案。
public class BigFileStream : Stream
{
FileStream inStream;
FileStream testStream;
String filePath;
internal BigFileStream(string filePath)
{
this.filePath = filePath;
inStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Write);
}
public override bool CanRead
{
get { return inStream.CanRead; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
throw new Exception("This stream does not support writing.");
}
public override long Length
{
get { throw new Exception("This stream does not support the Length property."); }
}
public override long Position
{
get
{
return inStream.Position;
}
set
{
throw new Exception("This stream does not support setting the Position property.");
}
}
public override int Read(byte[] buffer, int offset, int count)
{
int countRead = inStream.Read(buffer, offset, count);
if (countRead != 0)
{
return countRead;
}
else
{
for (int i = 1; i < 10; i++)
{
Thread.Sleep(i * 15);
countRead = inStream.Read(buffer, offset, count);
if (countRead != 0)
{
return countRead;
}
}
return countRead;
}
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new Exception("This stream does not support seeking.");
}
public override void SetLength(long value)
{
throw new Exception("This stream does not support setting the Length.");
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new Exception("This stream does not support writing.");
}
public override void Close()
{
inStream.Close();
base.Close();
}
protected override void Dispose(bool disposing)
{
inStream.Dispose();
base.Dispose(disposing);
}
}
return new BigFileStream(@"c:\test.txt");
public override int Read(byte[] buffer, int offset, int count)
{
int countRead = inStream.Read(buffer, offset, count);
if (countRead != 0)
{
return countRead;
}
else
{
Boolean fileAccessible = false;
while (!fileAccessible)
{
try
{
//try to open the file in Write, if it goes in exception, that means that the file is still opened by the writer
testStream = new FileStream(this.filePath, FileMode.Open, FileAccess.Write, FileShare.Read);
testStream.Close();
break;
}
catch (Exception e)
{
Thread.Sleep(500);
countRead = inStream.Read(buffer, offset, count);
if (countRead != 0)
{
return countRead;
}
}
}
countRead = inStream.Read(buffer, offset, count);
return countRead;
}
}