Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C&LINQ;将文件分组为5MB组_C#_Linq - Fatal编程技术网

C# C&LINQ;将文件分组为5MB组

C# C&LINQ;将文件分组为5MB组,c#,linq,C#,Linq,您好,我正在尝试编写一个Linq查询,在一个文件名列表上运行,该列表返回一个分组为5MB块的文件列表。因此,每个组将包含一个文件名列表,这些文件名的总/总MB最大为5MB 我同意Linq,但这次我不知道从哪里开始。帮助 DirectoryInfo di = new DirectoryInfo (@"x:\logs"); List<string> FileList = di.GetFiles ("*.xml") var Grouped = FileList => 是的,你可以和

您好,我正在尝试编写一个Linq查询,在一个文件名列表上运行,该列表返回一个分组为5MB块的文件列表。因此,每个组将包含一个文件名列表,这些文件名的总/总MB最大为5MB

我同意Linq,但这次我不知道从哪里开始。帮助

DirectoryInfo di = new DirectoryInfo (@"x:\logs");
List<string> FileList = di.GetFiles ("*.xml")
var Grouped = FileList =>

是的,你可以和LINQ一起做

var groupedFiles = files.Aggregate(
    new List<List<FileInfo>>(),
    (groups, file) => {
        List<FileInfo> group = groups.FirstOrDefault(
           g => g.Sum(f => f.Length) + file.Length <= 1024 * 1024 * 5
        );
        if (group == null) {
            group = new List<FileInfo>();
            groups.Add(group);
        }
        group.Add(file);
        return groups;
    }
);
这个算法是贪婪的。它只是找到了第一个可以将FileInfo放入的列表,而不会超过5MB的上限。这在最小化组数方面不是最优的,但您没有将其作为约束条件。我认为在调用Aggregate之前使用OrderByf=>f.Length会有所帮助,但我现在没有时间深入思考这个问题。

首先看一下。它解决了分组到子列表的问题。然后,技巧是检测GROUPBY子句中文件的大小。这可能是一个答案,不使用LINQ可能比使用LINQ更清楚

部分问题是您有一个文件名列表。您需要一个文件对象列表,以便可以通过LINQ查询文件的大小。在Linq 4.0中,您有一个应该是您想要的构造。

这里有一种方法:

定义一个类型,该类型以文件大小作为输入,并返回一个值,该值在达到指定的最大值并重置时递增。此类型负责维护自己的状态。 按此类型返回的值分组。 代码示例:

// No idea what a better name for this would be...
class MaxAmountGrouper
{
    readonly int _max;

    int _id;
    int _current;

    public MaxAmountGrouper(int max)
    {
        _max = max;
    }

    public int GetGroupId(int amount)
    {
        _current += amount;
        if (_current >= _max)
        {
            _current = 0;
            return _id++;
        }

        return _id;
    }
}
用法:

const int BytesPerMb = 1024 * 1024;

DirectoryInfo directory = new DirectoryInfo(@"x:\logs");
FileInfo[] files = directory.GetFiles("*.xml");

var grouper = new MaxAmountGrouper(5 * BytesPerMb);
var groups = files.GroupBy(f => grouper.GetGroupId((int)f.Length));

foreach (var g in groups)
{
    long totalSize = g.Sum(f => f.Length);
    Console.WriteLine("Group {0}: {1} MB", g.Key, totalSize / BytesPerMb);
    foreach (FileInfo f in g)
    {
        Console.WriteLine("File: {0} ({1} MB)", f.Name, f.Length / BytesPerMb);
    }
    Console.WriteLine();
}

我首先将文件列表抛出到SQL表中。类似于此,但包含大小列:

CREATE TABLE #DIR (fileName varchar(100))

INSERT INTO #DIR
EXEC master..xp_CmdShell 'DIR C:\RTHourly\*.xml /B'
然后是一个select语句,类似于:

SELECT *,
CASE WHEN SIZE < 5 THEN 1
WHEN SIZE < 10 THEN 2
...
END AS Grouping
FROM #DIR
ORDER BY Grouping, FileName, Size

要做到这一点,您必须在SQL Server上快速更改安全设置。查看博客帖子

感谢您的回复,您能展示命令式视角吗?@ZionGates:事实上,我认为LINQ解决方案还可以。强制性解决方案不会有太大不同。我认为这个解决方案是强制性的。您仅将foreach替换为Aggregate。Rest是普通的命令式代码。@Euphoric:同意,这就是为什么我同意这个解决方案,并声明命令式解决方案不会有太大的不同。这似乎是最简单的方法,谢谢。还有其他限制吗?比如最小组数?如果是,那么LINQ真的是个坏主意,因为这样的算法太复杂了。如果不是,那么LINQ只是个坏主意。只有当您立即知道如何编写查询时,才应该使用LINQ。如果您需要仔细考虑如何进行查询,那么以迭代方式解决它会更安全、更快。