我该如何简化?我试图根据目录和子目录的大小从目录和子目录中获取Excel文件的数量。我至少有10个不同的分组。
var queryList2Only = from i in di.GetFiles("*.xls", SearchOption.TopDirectoryOnly)
.Where(f => f.Length <= 5120)
select i.Length;
if (queryList2Only.Any())
{
dest.WriteLine("Excel File <= 5 KB");
dest.WriteLine(queryList2Only.Count());
dest.WriteLine("");
}
var queryList3Only = from i in di.GetFiles("*.xls", SearchOption.TopDirectoryOnly)
.Where(f => f.Length > 5120 && f.Length <= 10240)
select i.Length;
if (queryList3Only.Any())
{
dest.WriteLine("Excel File > 5 KB and <= 10 KB");
dest.WriteLine(queryList3Only.Count());
dest.WriteLine("");
编辑: 我需要这个
<= 5 KB,> 5 KB and <= 10 KB,> 10 KB and <= 20 KB,> 20 KB and <= 100 KB,> 100 KB and <= 1000 KB,> 1000 KB and <=5 MB,> 5 MB and <=10 MB,> 10 MB and <=20 MB,> 20 MB and <=50 MB,> 50 MB and <=100 MB
private void button1_Click(object sender, EventArgs e)
{
DirectoryInfo Folder = new DirectoryInfo(textBox1.Text);
var _logFolderPath4 = Path.Combine(textBox1.Text.Trim(), "log");
if (Folder.Exists)
if (!Directory.Exists(_logFolderPath4))
Directory.CreateDirectory(_logFolderPath4);
DirectoryInfo di = new DirectoryInfo(@"D:\Material\");
bool time = false;
using (var dest = File.AppendText(Path.Combine(_logFolderPath4, "Excel.txt")))
{
if (!time)
{
dest.WriteLine("---------------------" + DateTime.Now + "---------------------");
dest.WriteLine("");
time = true;
}
CountFiles(dest, di, @"*.txt");
}
}
答案 0 :(得分:4)
您需要在集合中包含范围,并对其进行枚举。 这是一个应该让你前进的例子 - sizes数组包含步骤,当然你应该选择对你的应用程序有意义的步骤:
int[] sizes = Enumerable.Range(0,10).Select(n => (int)Math.Pow(2,n + 8)).ToArray();
int lower = 0;
foreach(var size in sizes)
{
var files = di.GetFiles("*.*").Where(f => f.Length >= lower && f.Length < size);
Console.WriteLine("Between {0} and {1} bytes:", lower,size);
foreach(var file in files)
Console.WriteLine("\t{0}",file);
lower = size;
}
答案 1 :(得分:2)
您不一定需要LINQ。你可以更有效地循环它。虽然Rup的解决方案在这里很好地利用了LINQ。
这是一个更完整的版本,专门针对您想要做的事情。
// count it
CountFiles(dest, di, @"*.xls");
public void CountFiles(TextWriter writer, DirectoryInfo directory, string searchPattern)
{
var counter = new FileGroupCounter
{
{ 5, Multiplier.K },
{ 10, Multiplier.K },
{ 20, Multiplier.K },
{ 100, Multiplier.K },
{ 1000, Multiplier.K },
{ 5, Multiplier.M },
{ 10, Multiplier.M },
{ 20, Multiplier.M },
{ 50, Multiplier.M },
{ 100, Multiplier.M },
};
foreach (var file in directory.EnumerateFiles(searchPattern, SearchOption.AllDirectories))
// or use GetFiles() if you're not targeting .NET 4.0
{
counter.CountFile(file);
}
foreach (var result in counter)
{
writer.WriteLine("Excel File " + result);
writer.WriteLine(result.Count);
writer.WriteLine();
}
}
// and the supporting classes
public enum Multiplier : long
{
K = 1 << 10,
M = 1 << 20,
G = 1 << 30,
T = 1 << 40,
}
public class FileGroupCounter : IEnumerable<FileGroupCounter.Result>
{
public ReadOnlyCollection<long> Limits { get { return roLimits; } }
public ReadOnlyCollection<int> Counts { get { return roCounts; } }
public ReadOnlyCollection<Multiplier> Multipliers { get { return roMultipliers; } }
public FileGroupCounter()
{
limits = new List<long>();
counts = new List<int>();
multipliers = new List<Multiplier>();
roLimits= limits.AsReadOnly();
roCounts= counts.AsReadOnly();
roMultipliers= multipliers.AsReadOnly();
}
private List<long> limits;
private List<int> counts;
private List<Multiplier> multipliers;
private ReadOnlyCollection<long> roLimits;
private ReadOnlyCollection<int> roCounts;
private ReadOnlyCollection<Multiplier> roMultipliers;
private long CalculateLength(int index)
{
return limits[index] * (long)multipliers[index];
}
public void Add(long limit, Multiplier multiplier)
{
int lastIndex = limits.Count - 1;
if (lastIndex >= 0 && limit * (long)multiplier <= CalculateLength(lastIndex))
throw new ArgumentOutOfRangeException("limit, multiplier", "must be added in increasing order");
limits.Add(limit);
counts.Add(0);
multipliers.Add(multiplier);
}
public bool CountFile(FileInfo file)
{
if (file == null)
throw new ArgumentNullException("file");
for (int i = 0; i < limits.Count; i++)
{
if (file.Length <= CalculateLength(i))
{
counts[i]++;
return true;
}
}
return false;
}
public IEnumerator<Result> GetEnumerator()
{
for (int i = 0; i < limits.Count; i++)
{
if (counts[i] > 0)
yield return new Result(this, i);
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
public class Result
{
public long Limit { get { return counter.limits[index]; } }
public int Count { get { return counter.counts[index]; } }
public Multiplier Multiplier { get { return counter.multipliers[index]; } }
internal Result(FileGroupCounter counter, int index)
{
this.counter = counter;
this.index = index;
}
private FileGroupCounter counter;
private int index;
public override string ToString()
{
if (index > 0)
return String.Format("> {0} {1}B and <= {2} {3}B",
counter.limits[index - 1], counter.multipliers[index - 1],
counter.limits[index], counter.multipliers[index]);
else
return String.Format("<= {0} {1}B",
counter.limits[index], counter.multipliers[index]);
}
}
}
答案 2 :(得分:2)
我认为这里只有真正的优化才能确保你只调用di.GetFiles("*.xls", SearchOption.TopDirectoryOnly)
一次 - 因为这实际上会触及文件系统,而不是像大多数LINQ那样懒惰地执行。当然,文件系统会缓存这个结果,但不能慢于保留在内存中并重用列表。
一旦你记忆中,杰夫可能是对的 - 只考虑自己 - 认为这看起来并不优雅:-)除非你处理大量数据,否则它可能没有太大的区别。您只想尝试保持分配/重新分配的数量。我可以尽可能多地使用LINQ
var files = di.GetFiles("*.xls", SearchOption.TopDirectoryOnly);
// map to a list of numbers, 0 = up to 5K, 1 = 5-10, etc.
var sizes = files.Select(f => (f.Length / 5120));
var countsBySize = sizes.GroupBy(s => s)
.Select(g => new { Size = g.Key, Count = g.Count() })
.OrderBy(s => s.Size);
var results = countBySize.ToList();
返回每个桶中5K桶和文件数的列表。如果你只是要预先做到这一点,那就不要做最后的ToList。如果你想要每个桶中的单个文件,你应该按(f.Length / 5120)进行分组而不先选择它。