Export a folder's file list to CSV or Excel in C#
An inventory of files, with names, sizes and dates, is a common request from people who want to sort and filter it in Excel. DirectoryInfo gives you the data; writing a CSV that Excel opens without mangling accents or dates takes a few precautions.
Collect the data
using System.IO;
using System.Linq;
var root = new DirectoryInfo(@"D:\Shared\Projects");
var files = root.EnumerateFiles("*", SearchOption.AllDirectories)
.Select(f => new
{
Folder = Path.GetRelativePath(root.FullName, f.DirectoryName), // .NET Core 2.0+; see note
f.Name,
f.Extension,
f.Length,
f.LastWriteTimeUtc
})
.ToList();
Path.GetRelativePath does not exist on .NET Framework; there, use f.DirectoryName.Substring(root.FullName.Length).TrimStart('\\'). If some subfolders are unreadable, use the safe enumeration shown in List files recursively.
Write CSV
using System.Globalization;
using System.Text;
static string Q(string s) =>
s.IndexOfAny(new[] { ',', '"', '\r', '\n' }) >= 0 ? "\"" + s.Replace("\"", "\"\"") + "\"" : s;
var sb = new StringBuilder();
sb.AppendLine("Folder,Name,Extension,SizeBytes,ModifiedUtc");
foreach (var f in files)
{
sb.Append(Q(f.Folder)).Append(',')
.Append(Q(f.Name)).Append(',')
.Append(Q(f.Extension)).Append(',')
.Append(f.Length.ToString(CultureInfo.InvariantCulture)).Append(',')
.AppendLine(f.LastWriteTimeUtc.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
}
File.WriteAllText(@"D:\Exports\files.csv", sb.ToString(), new UTF8Encoding(true)); // with BOM
- BOM: Excel detects UTF-8 reliably only when the file starts with a byte order mark; without it, accented file names appear garbled.
- Separator: Excel uses the list separator from the regional settings. In many European locales it is a semicolon, so a comma-separated file opens in one column. Either write semicolons for those users, or add a first line
sep=,, which Excel understands (other programs will show it as data). - Quoting: file names may contain commas; the
Qhelper quotes such fields as RFC 4180 describes. - Dates and numbers in an invariant format avoid confusion between day/month orders.
Write a real .xlsx
To avoid separator and encoding questions entirely, create a workbook with ClosedXML (see Export GridView data to Excel for setup):
using ClosedXML.Excel;
using (var wb = new XLWorkbook())
{
var ws = wb.Worksheets.Add("Files");
ws.Cell(1, 1).InsertTable(files); // header row from property names, formatted as a table
ws.Columns().AdjustToContents();
wb.SaveAs(@"D:\Exports\files.xlsx");
}
Sizes stay numeric and dates stay dates, so users can sort and sum them immediately.
From an ASP.NET page
Instead of saving to disk, send the bytes as a download with Content-Disposition: attachment, as in the GridView export article. Only list folders the application controls, and remember the application pool identity needs read access to them.
Large folders
For hundreds of thousands of files, building the whole CSV in a StringBuilder uses a lot of memory. Write directly to a StreamWriter created with new StreamWriter(path, false, new UTF8Encoding(true)) and write one line per file as you enumerate. The output is identical and memory use stays flat.
Official documentation
- Microsoft Learn: DirectoryInfo.EnumerateFiles, Path.GetRelativePath, UTF8Encoding constructor
- IETF: RFC 4180, CSV format