将(n)附加到文件名(不使用system.io.file)以确保唯一名称

时间:2014-08-19 19:30:29

标签: c# loops collections zipfile

我有一个包含文件名和类文件数据的类:

public class FileMeta
{
    public string FileName { get; set; }
    public byte[] FileData { get; set; }
}

我有一个通过异步下载操作填充此类集合的方法(文件不是来自本地文件系统):

async Task<List<FileMeta>> ReturnFileData(IEnumerable<string> urls)
{
    using (var client = new HttpClient())
    {
        var results = await Task.WhenAll(urls.Select(async url => new
        {
            FileName = Path.GetFileName(url),
            FileData = await client.GetByteArrayAsync(url),
        }));
        return results.Select(result => 
            new FileMeta
            {
                FileName = result.FileName, 
                FileData = result.FileData
            }).ToList();
    }
}

我将这个List<FileMeta>提供给ZipFile创建者,ZipFile就像所有文件容器一样需要唯一的文件名。

可读性很重要,我希望能够做到以下几点:

file.txt => file.txt
file.txt => file(1).txt
file.txt => file(2).txt

有很多关于如何在文件系统中执行此操作的示例,但不包含简单的对象集合。 (例如,使用System.IO.File.Exists

循环访问此对象集合并返回一组唯一文件名的最佳方法是什么?

我已经走了多远

private List<FileMeta> EnsureUniqueFileNames(IEnumerable<FileMeta> fileMetas)
{
    var returnList = new List<FileMeta>();
    foreach (var file in fileMetas)
    {
        while (DoesFileNameExist(file.FileName, returnList))
        {
             //Append (n) in sequence until match is not found?
        }
    }
    return returnList;
}

private bool DoesFileNameExist(string fileName, IEnumerable<FileMeta> fileMeta)
{
    var fileNames = fileMeta.Select(file => file.FileName).ToList();
    return fileNames.Contains(fileName);
}

1 个答案:

答案 0 :(得分:1)

您可以尝试以下方法来增加文件名:

private List<FileMeta> EnsureUniqueFileNames(IEnumerable<FileMeta> fileMetas)
{
    var returnedList = new List<FileMeta>();
    foreach (var file in fileMetas)
    {
        int count = 0;
        string originalFileName = file.FileName;
        while (returnedList.Any(fileMeta => fileMeta.FileName.Equals(file.FileName, 
                                            StringComparison.OrdinalIgnoreCase))
        {
            string fileNameOnly = Path.GetFileNameWithoutExtension(originalFileName);
            string extension = Path.GetExtension(file.FileName);
            file.FileName = string.Format("{0}({1}){2}", fileNameOnly, count, extension);
            count++;
        }

        returnList.Add(file);
    }
    return returnList;
}

作为附注,在ReturnFileData中,您生成了两个列表,一个是匿名类型,另一个是实际的FileMeta类型。您可以减少中间列表的创建。实际上,根本不需要await方法内部:

private Task<FileMeta[]> ReturnFileDataAsync(IEnumerable<string> urls)
{
    var client = new HttpClient();
    return Task.WhenAll(urls.Select(async url => new FileMeta
    {
        FileName = Path.GetFileName(url),
        FileData = await client.GetByteArrayAsync(url),
    }));
}

我将返回类型设为FileMeta[]而不是List<FileMeta>,因为它无论如何都是固定大小的返回,并且减少了在返回的数组上调用ToList的需要。我还添加了Async后缀,以遵循TAP指南。