话不多说,直接上代码:
/// <summary>
/// FileStream循环读取大文件
/// </summary>
/// <param name="path">要读取的大文件地址</param>
/// <param name="LastReadPosition">上一次读取结束时的流的位置 => fs.Position</param>
/// <returns>本次读取结束时,流所在的位置(fs.Position或fs.Length)</returns>
public static long DoParse_FileStream(string path, long LastReadPosition)
{
int bufferSize = 1024 * 1024; // 缓冲区大小,一次最多读取该数目的字节。
byte[] buffer = new byte[bufferSize]; // 缓冲区
Encoding encode = Encoding.UTF8; // 文本所用的编码
string dataStr = string.Empty; // 存储每次读取出的字符串
List<string> dataList = new List<string>(); // 用换行符分隔后的每行数据
int len = 0; // 每次读取到缓冲区的字节数
int index = 1; // 当前读取到多少行
string separator = "\n"; // 每行之间的分隔符
string halfLine = string.Empty; // 每次分隔时出现的半行字符串
try
{
using (FileStream fs = new FileStream(path, FileMode.Open))
{
fs.Seek(LastReadPosition, SeekOrigin.Begin); // 设置文件流的读取位置
while ((len = fs.Read(buffer, 0, buffer.Length)) > 0)
{
dataStr = encode.GetString(buffer); // 将读取出的字节数组按编码转换为字符串
dataList = dataStr.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries).ToList();
for (int i = 0; i < dataList.Count; i++)
{
if (i == 0)
{
dataList[i] = halfLine + dataList[i]; // 将上次读取最后的半行和本次读取的第一行合并,凑成完整的一行。
}
if (i == dataList.Count - 1)
{
if (Regex.IsMatch(dataStr, separator + @"\s*$"))
{
halfLine = string.Empty; // 当读取的内容为完整的行,设置halfLine为空值。
}
else
{
halfLine = dataList[i]; // 当读取的内容不完整时,最后一项会是半行数据。
continue;
}
}
#region 在这里循环遍历每一行数据
Console.WriteLine(index + ": " + dataList[i]); // 这就是完整的每行数据
index++;
#endregion
}
buffer = new byte[bufferSize]; // 每次fs读取前都需要先将buffer置为空,因为fs会将读取的内容“替换”到buffer的指定位置,当读取到最后一次时会出现冗余数据。
}
LastReadPosition = fs.Position; // 设置本次读取到的位置
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return LastReadPosition;
}
使用说明:
1、使用时,直接在“#region 在这里循环遍历每一行数据”中编辑每一行即可。
2、每次读取出的buffer内容,应该是多行数据。以上代码中设置的buffer.Length为1024*1024,也即1M,每次可以读取出几百甚至上千行数据。
网友评论