C
C#2y ago
nks1fu

❔ ✅ Creating a console application in C# that utilizes async/await functions.

hi so i have to create a console application and the porpuse is to etrieve information on file sizes and the number of files in a specified directory. Your application should be able to handle multiple directory paths as input. there were asyinc functions i had to use and want to see anyway i can change it for the better or make it simpler
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace FileSizeCalculator
{
class Program
{
static async Task Main(string[] args)
{

Console.WriteLine("Enter directory paths separated by commas:");
string input = Console.ReadLine();
List<string> directoryPaths = new List<string>(input.Split(','));

long totalSize = await GetTotalSizeAsync(directoryPaths);


Console.WriteLine($"Total number of files: {GetFileCount(directoryPaths)}");
Console.WriteLine($"Total size of files (bytes): {totalSize}");
}

static async Task<int> GetFileCountAsync(string directoryPath)
{
string[] files = await Task.Run(() => Directory.GetFiles(directoryPath));
return files.Length;
}

static async Task<long> GetFileSizeAsync(string filePath)
{

FileInfo fileInfo = await Task.Run(() => new FileInfo(filePath));
return fileInfo.Length;
}


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace FileSizeCalculator
{
class Program
{
static async Task Main(string[] args)
{

Console.WriteLine("Enter directory paths separated by commas:");
string input = Console.ReadLine();
List<string> directoryPaths = new List<string>(input.Split(','));

long totalSize = await GetTotalSizeAsync(directoryPaths);


Console.WriteLine($"Total number of files: {GetFileCount(directoryPaths)}");
Console.WriteLine($"Total size of files (bytes): {totalSize}");
}

static async Task<int> GetFileCountAsync(string directoryPath)
{
string[] files = await Task.Run(() => Directory.GetFiles(directoryPath));
return files.Length;
}

static async Task<long> GetFileSizeAsync(string filePath)
{

FileInfo fileInfo = await Task.Run(() => new FileInfo(filePath));
return fileInfo.Length;
}


`
21 Replies
nks1fu
nks1fuOP2y ago
static async Task<long> GetTotalSizeAsync(List<string> directoryPaths)
{
long totalSize = 0;


await Task.WhenAll(directoryPaths.Select(async directoryPath =>
{

string[] files = await Task.Run(() => Directory.GetFiles(directoryPath));
foreach (string file in files)
{
totalSize += await GetFileSizeAsync(file);
}
}));

return totalSize;
}

static int GetFileCount(List<string> directoryPaths)
{
int totalFileCount = 0;


foreach (string directoryPath in directoryPaths)
{

string[] files = Directory.GetFiles(directoryPath);
totalFileCount += files.Length;
}

return totalFileCount;
}
}
}
static async Task<long> GetTotalSizeAsync(List<string> directoryPaths)
{
long totalSize = 0;


await Task.WhenAll(directoryPaths.Select(async directoryPath =>
{

string[] files = await Task.Run(() => Directory.GetFiles(directoryPath));
foreach (string file in files)
{
totalSize += await GetFileSizeAsync(file);
}
}));

return totalSize;
}

static int GetFileCount(List<string> directoryPaths)
{
int totalFileCount = 0;


foreach (string directoryPath in directoryPaths)
{

string[] files = Directory.GetFiles(directoryPath);
totalFileCount += files.Length;
}

return totalFileCount;
}
}
}
nks1fu
nks1fuOP2y ago
Becquerel
Becquerel2y ago
the main thing you need to learn about is the difference between io-bound and cpu-bound work there's not much gain to taking io-bound work like this and wrapping it up in task.run more specifically, this is very quick io-bound work - which is why the methods don't natively have async versions (whereas, say, File.ReadAllTextAsync does exist) generally, you would use Task.Run to push cpu-bound work onto another thread i get the impulse to see anything to do with files, directories etc and to make it async - done it myself but if the .NET core library doesn't get you an ...Async method it's probably because it's not necessary or it's not possible (such as due to missing APIs from the underlying operating system) for what it's worth your use of await Task.WhenAll looks good 👍 though you could probably await everything into a long[] and then use LINQ's .Sum() to make it cleaner and avoid having a lambda capture the local variable totalSize
nks1fu
nks1fuOP2y ago
the Task.WhenAll ?
Becquerel
Becquerel2y ago
yeah conceptually you're taking a string, the directoryPath, and turning it into longs you could do that for all of them to get a big long[] then do:
private long[] GetSizes(string directory)
{
return new DirectoryInfo(directory)
.EnumerateFiles()
.Select(file => new FileInfo(file))
.Select(fileInfo => fileInfo.Length)
.ToArray();
}

var sizes = directoryPaths.Select(GetSizes);

return sizes.Sum();
private long[] GetSizes(string directory)
{
return new DirectoryInfo(directory)
.EnumerateFiles()
.Select(file => new FileInfo(file))
.Select(fileInfo => fileInfo.Length)
.ToArray();
}

var sizes = directoryPaths.Select(GetSizes);

return sizes.Sum();
nks1fu
nks1fuOP2y ago
namespace FileSizeCalculator
{
class Program
{
static async Task Main(string[] args)
{

Console.WriteLine("Enter directory paths separated by commas:");
string input = Console.ReadLine();
List<string> directoryPaths = new List<string>(input.Split(','));

long[] sizes = await GetTotalSizeAsync(directoryPaths);
long totalSize = sizes.Sum();


Console.WriteLine($"Total number of files: {GetFileCount(directoryPaths)}");
Console.WriteLine($"Total size of files (bytes): {totalSize}");
}
namespace FileSizeCalculator
{
class Program
{
static async Task Main(string[] args)
{

Console.WriteLine("Enter directory paths separated by commas:");
string input = Console.ReadLine();
List<string> directoryPaths = new List<string>(input.Split(','));

long[] sizes = await GetTotalSizeAsync(directoryPaths);
long totalSize = sizes.Sum();


Console.WriteLine($"Total number of files: {GetFileCount(directoryPaths)}");
Console.WriteLine($"Total size of files (bytes): {totalSize}");
}
i cant use that yet
Becquerel
Becquerel2y ago
oh is it one of those things where your teacher doesn't let you use certain language features until they say so my condolences
nks1fu
nks1fuOP2y ago
i am just scared cuz staff is gonna check it with there own developer wanted to see is there a way to make it better wanted to check all the boxes
Becquerel
Becquerel2y ago
depends on what 'better' means
nks1fu
nks1fuOP2y ago
improve it like not making it dry do u think its good enough?
Becquerel
Becquerel2y ago
there are things i would change, like using var everywhere, and ditching the Task.Run stuff as i mentioned but it's fine it looks like it would work and you have split up the code into methods of appropriate size
nks1fu
nks1fuOP2y ago
oh ok thank you for the help i was worrying alot ty so muchh and have a nice day
Becquerel
Becquerel2y ago
no prob. if you're a beginner then this is way better than most beginner code
nks1fu
nks1fuOP2y ago
ty man and one more question do i need to close the post?
Becquerel
Becquerel2y ago
i don't think you have to but you can oh i guess i can do it too lmao
nks1fu
nks1fuOP2y ago
lol ty again
Florian Voß
Florian Voß2y ago
I have a question regarding this too. Does it matter if we do GetFiles().Length or EnumerateFiles().Count()? which is better? I guess EnumerateFiles should be better because it doesnt load all of the filenames into memory at once but evaluates lazily?
Becquerel
Becquerel2y ago
if you mean the snippet i posted, when .ToArray() is called it will load everything into memory at once anyway the purpose of using EnumerateFiles is that, as an IEnumerable, it lets you chain together operations like .Select which are executed as a single operation when you enumerate the collection which makes simpler code than writing manual foreach loops, etc i don't think there would be much of a performance difference
Florian Voß
Florian Voß2y ago
didnt even see your snippt tbh but GetFiles() would also allow you to chain other linq operations
Becquerel
Becquerel2y ago
oh, right probably no real difference in that case
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server