StreamReader.ReadLine() 不消耗流
StreamReader.ReadLine() doesn't consume the stream
我正在开始一个新的 Web 应用程序项目,用户可以在其中上传 .csv
文件,以便我可以处理该文件。
目前我可以让用户上传文件,但是当我尝试使用 StreamReader
从文件生成的流中读取时,似乎 StreamReader
无法读取从流正确。
顺便说一句,对于上传文件部分,我遵循了微软教程here
这是视图的代码。
<form method="post" enctype="multipart/form-data" asp-controller="Upload" asp-action="Upload">
<div class="form-group">
<div class="col-md-10">
<p>Upload one or more files using this form:</p>
<input type="file" name="files" >
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Upload" />
</div>
</div>
这是我的控制器代码
len、len2 和 p 是用于调试目的的变量。
[HttpPost]
public async Task<IActionResult> Upload(IFormFile file)
{
if (file != null && file.Length > 0)
{
var filePath = Path.GetTempFileName(); //Note: May throw excepetion when temporary file exceeds 65535 per server
var stream = new FileStream(filePath, FileMode.Create);
await file.CopyToAsync(stream);//
long len = stream.Length;// 412 bytes
StreamReader reader = new StreamReader(stream);//*
int p = reader.Peek();//currently the next character is EoF
var val = reader.ReadLine();
long len2 = stream.Length;// 412 bytes
bool end = reader.EndOfStream;// true
//do some stuff here
return RedirectToAction("Success");
}
else
{
return RedirectToAction("Upload_fail");//file not found
}
}
如有任何建议或帮助,我们将不胜感激。
从流中读取时,当前位置会相应更新。例如,想象以下步骤:
- 位置从 0(流的开头)开始。
- 读取一个字节 - 这会将位置更新为 1。
- 读取另一个字节 - 这会将位置更新为 2。
如果流中只有两个字节,则该位置现在被认为是 EOF - 不再可能读取额外的字节,因为它们已经被读取了。
关于您的示例,对 await file.CopyToAsync(stream)
的调用将流的位置推进到 EOF。因此,当您将 StreamReader
包裹在它周围时,就没有什么可读的了。写入的过程相同 - CopyToAsync
操作同时推进输入和输出流,导致操作完成后两个流都处于 EOF。
让事情稍微复杂一点的是,Streams 可以是只向前的,这意味着一旦数据被读取就不可能向后返回。当您使用 FileStream
时,我认为您可以回到开头,就像这样:
await file.CopyToAsync(stream);
stream.Position = 0;
您也可以使用 stream.Seek(0, SeekOrigin.Begin)
,如本回答所述:Stream.Seek(0, SeekOrigin.Begin) or Position = 0
我正在开始一个新的 Web 应用程序项目,用户可以在其中上传 .csv
文件,以便我可以处理该文件。
目前我可以让用户上传文件,但是当我尝试使用 StreamReader
从文件生成的流中读取时,似乎 StreamReader
无法读取从流正确。
顺便说一句,对于上传文件部分,我遵循了微软教程here
这是视图的代码。
<form method="post" enctype="multipart/form-data" asp-controller="Upload" asp-action="Upload">
<div class="form-group">
<div class="col-md-10">
<p>Upload one or more files using this form:</p>
<input type="file" name="files" >
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Upload" />
</div>
</div>
这是我的控制器代码
len、len2 和 p 是用于调试目的的变量。
[HttpPost]
public async Task<IActionResult> Upload(IFormFile file)
{
if (file != null && file.Length > 0)
{
var filePath = Path.GetTempFileName(); //Note: May throw excepetion when temporary file exceeds 65535 per server
var stream = new FileStream(filePath, FileMode.Create);
await file.CopyToAsync(stream);//
long len = stream.Length;// 412 bytes
StreamReader reader = new StreamReader(stream);//*
int p = reader.Peek();//currently the next character is EoF
var val = reader.ReadLine();
long len2 = stream.Length;// 412 bytes
bool end = reader.EndOfStream;// true
//do some stuff here
return RedirectToAction("Success");
}
else
{
return RedirectToAction("Upload_fail");//file not found
}
}
如有任何建议或帮助,我们将不胜感激。
从流中读取时,当前位置会相应更新。例如,想象以下步骤:
- 位置从 0(流的开头)开始。
- 读取一个字节 - 这会将位置更新为 1。
- 读取另一个字节 - 这会将位置更新为 2。
如果流中只有两个字节,则该位置现在被认为是 EOF - 不再可能读取额外的字节,因为它们已经被读取了。
关于您的示例,对 await file.CopyToAsync(stream)
的调用将流的位置推进到 EOF。因此,当您将 StreamReader
包裹在它周围时,就没有什么可读的了。写入的过程相同 - CopyToAsync
操作同时推进输入和输出流,导致操作完成后两个流都处于 EOF。
让事情稍微复杂一点的是,Streams 可以是只向前的,这意味着一旦数据被读取就不可能向后返回。当您使用 FileStream
时,我认为您可以回到开头,就像这样:
await file.CopyToAsync(stream);
stream.Position = 0;
您也可以使用 stream.Seek(0, SeekOrigin.Begin)
,如本回答所述:Stream.Seek(0, SeekOrigin.Begin) or Position = 0