文件有 1.5G ,目前采用的读取方法
using (var reader = new BinaryReader(new FileStream(FileStorePathTable, FileMode.Open), Encoding.ASCII))
{
// ...
}
请问有没有性能更好的方法?
大文件处理最快的据说是内存映射文件,没怎么具体测试过。
你这样一次读取全部的字节, 估计会很慢吧,是不是考虑 分段读取 ,一次读10M 这种
FileStream~~理解Stream和File.ReadAll的区别。
FileStream的操作方式已经透明了Buffer的实现过程。
如果只执行读和保存,上述Reader和Writer默认参数方式肯定不会达到10M。
若题主并不会具体操作具体的byte,也不想跳过文件系统,可以换个Reader,调整Buffer参数(如跟文件系统的块成倍数关系)。
剥离中间过程,如跳过文件系统,直接读取扇区。
若题主并不会具体操作具体的byte,也不想跳过文件系统,可以换个Reader,调整Buffer参数(如跟文件系统的块成倍数关系,Buffer.Size 的倍数n大于等于1倍文件系统的块大小)。
public FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync)
是附带了Buffer这个参数的,你可以根据自己的文件系统块大小调整。
如果是Win,直接win32读肯定也要快一些(算是跳过.net的过程,比如上面有安全句柄),自行Buffer,然后操作读写;
内存映射
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
namespace ConsoleDemo
{
class Program
{
private const string TXT_FILE_PATH = @"E:\开源学习\超大文本文件读取\File\a.txt";
private const string SPLIT_VARCHAR = "囧";
private const char SPLIT_CHAR = '囧';
private static long FILE_SIZE = 0;
static void Main(string[] args)
{
//long ttargetRowNum = 39999999;
long ttargetRowNum = 10000000;
DateTime beginTime = DateTime.Now;
string line = CreateMemoryMapFile(ttargetRowNum);
double totalSeconds = DateTime.Now.Subtract(beginTime).TotalSeconds;
Console.WriteLine(line);
Console.WriteLine(string.Format("查找第{0}行,共耗时:{1}s", ttargetRowNum, totalSeconds));
Console.ReadLine();
}
/// <summary>
/// 创建内存映射文件
/// </summary>
private static string CreateMemoryMapFile(long ttargetRowNum)
{
string line = string.Empty;
using (FileStream fs = new FileStream(TXT_FILE_PATH, FileMode.Open, FileAccess.ReadWrite))
{
long targetRowNum = ttargetRowNum + 1;//目标行
long curRowNum = 1;//当前行
FILE_SIZE = fs.Length;
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(fs, "test", fs.Length, MemoryMappedFileAccess.ReadWrite, null, HandleInheritability.None, false))
{
long offset = 0;
//int limit = 250;
int limit = 200;
try
{
StringBuilder sbDefineRowLine = new StringBuilder();
do
{
long remaining = fs.Length - offset;
using (MemoryMappedViewStream mmStream = mmf.CreateViewStream(offset, remaining > limit ? limit : remaining))
{
offset += limit;
using (StreamReader sr = new StreamReader(mmStream))
{
string ss = sr.ReadToEnd().ToString().Replace("\n", SPLIT_VARCHAR).Replace(Environment.NewLine, SPLIT_VARCHAR);
if (curRowNum <= targetRowNum)
{
if (curRowNum < targetRowNum)
{
string s = sbDefineRowLine.ToString();
int pos = s.LastIndexOf(SPLIT_CHAR);
if (pos > 0)
sbDefineRowLine.Remove(0, pos);
}
else
{
line = sbDefineRowLine.ToString();
return line;
}
if (ss.Contains(SPLIT_VARCHAR))
{
curRowNum += GetNewLineNumsOfStr(ss);
sbDefineRowLine.Append(ss);
}
else
{
sbDefineRowLine.Append(ss);
}
}
sr.Dispose();
}
mmStream.Dispose();
}
} while (offset < fs.Length);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return line;
}
}
}
private static long GetNewLineNumsOfStr(string s)
{
string[] _lst = s.Split(SPLIT_CHAR);
return _lst.Length - 1;
}
}
}
用磁盘阵列存储文件,比如RAID Level 0,理论上读取速度是放在一块磁盘上的n倍(n是磁盘数量)。或者通过代码把大文件拆分后分别保存到不同的磁盘上,读取的时候几个磁盘一起读,然后再合并。
参考资料:How to read a binary file quickly in c#? (ReadOnlySpan vs MemoryStream)
– dudu 4年前