首页 新闻 会员 周边

.NET Core 中读取超过大文件的性能更好的方法

0
悬赏园豆:100 [待解决问题]

文件有 1.5G ,目前采用的读取方法

using (var reader = new BinaryReader(new FileStream(FileStorePathTable, FileMode.Open), Encoding.ASCII))
{
    // ...             
}

请问有没有性能更好的方法?

dudu的主页 dudu | 高人七级 | 园豆:31007
提问于:2020-09-12 21:30
< >
分享
所有回答(5)
0

大文件处理最快的据说是内存映射文件,没怎么具体测试过。

天方 | 园豆:5407 (大侠五级) | 2020-09-12 22:13
0

你这样一次读取全部的字节, 估计会很慢吧,是不是考虑 分段读取 ,一次读10M 这种

兴想事成 | 园豆:540 (小虾三级) | 2020-09-13 23:08

FileStream~~理解Stream和File.ReadAll的区别。

FileStream的操作方式已经透明了Buffer的实现过程。

如果只执行读和保存,上述Reader和Writer默认参数方式肯定不会达到10M。

若题主并不会具体操作具体的byte,也不想跳过文件系统,可以换个Reader,调整Buffer参数(如跟文件系统的块成倍数关系)。

支持(0) 反对(0) 花飘水流兮 | 园豆:13560 (专家六级) | 2020-09-14 12:05
0

剥离中间过程,如跳过文件系统,直接读取扇区。

花飘水流兮 | 园豆:13560 (专家六级) | 2020-09-14 11:55

若题主并不会具体操作具体的byte,也不想跳过文件系统,可以换个Reader,调整Buffer参数(如跟文件系统的块成倍数关系,Buffer.Size 的倍数n大于等于1倍文件系统的块大小)。

支持(0) 反对(0) 花飘水流兮 | 园豆:13560 (专家六级) | 2020-09-14 12:05

public FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync)

是附带了Buffer这个参数的,你可以根据自己的文件系统块大小调整。

如果是Win,直接win32读肯定也要快一些(算是跳过.net的过程,比如上面有安全句柄),自行Buffer,然后操作读写;

支持(0) 反对(0) 花飘水流兮 | 园豆:13560 (专家六级) | 2020-09-14 12:24
0

内存映射

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;
    }
}

}

智客工坊 | 园豆:1855 (小虾三级) | 2020-09-14 13:32
0

用磁盘阵列存储文件,比如RAID Level 0,理论上读取速度是放在一块磁盘上的n倍(n是磁盘数量)。或者通过代码把大文件拆分后分别保存到不同的磁盘上,读取的时候几个磁盘一起读,然后再合并。

会长 | 园豆:12401 (专家六级) | 2020-09-15 12:08
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册