如何遍历数据并每n个条目创建一个新的文本文件

时间:2019-03-29 20:47:02

标签: c#

我正在列出需要添加到.txt文件(带有制表符分隔)的行列表。文本文件最多需要包含500个条目和一个标题。

现在,我有了这段代码,它可以成功地遍历列表并创建带有标题的文本文件。如果该文件已经存在,它将在我的列表中添加行而不添加标题。

在我的第一个文件超过500个条目之后,我不太清楚如何制作一个新文件,添加标题并添加每一行。

您能帮我将500个带有标题的行文件分开吗?谢谢

这是我到目前为止的代码:

var tab = new StringBuilder();

    foreach (var line in textlinestoadd)
    {
        tab.AppendLine(line.ToString());
    }

    if (!File.Exists(textcsvpath))
    {
        string textheader = "Vendor\tDate\tInvoice\tPO\tTax\tTotal\tAcount\tType\tJobs\tClass" +        Environment.NewLine;
        File.WriteAllText(textcsvpath, textheader);
    }
    File.AppendAllLines(textcsvpath, textlinestoadd);

4 个答案:

答案 0 :(得分:0)

这似乎是一个很好的练习机会,所以我将代码部分留作练习!

基本思想很简单。每当您写500行时,只需重置并写入新文件

这是高级伪代码

Initialize StringBuilder sb
For each line do 
    Add line to sb

    if line count == 500 then 
        save to file
        reset sb
        reset line count
        update filename = next file
    end if
End For

//writes the last chunk if # of lines is not multiple of 500
if line count is not 0 then 
    save to file
end if

答案 1 :(得分:0)

我会尝试这样的事情。

var tab = new StringBuilder();
int lineCount = 0;
string textheader = "Vendor\tDate\tInvoice\tPO\tTax\tTotal\tAcount\tType\tJobs\tClass" + Environment.NewLine;

if (File.Exists(textcsvpath)) {
    FileStream fs = File.OpenRead(textcsvpath);
    string[] fileContent = File.ReadAllLines(textcsvpath);
    lineCount = fileContent.Length - 1; // assume the first line is the header
}

foreach (var line in textlinestoadd)
{
    tab.AppendLine(line.ToString());
    lineCount++;
    if (lineCount > 0 && lineCount % 500 == 0)
    {
        if (!File.Exists(textcsvpath))
        {
            File.WriteAllText(textcsvpath, textheader);
        }
        File.AppendAllText(textcsvpath, tab.ToString());
        tab.Clear();
        textcsvpath = "some-new-file-name";
    }
}
if (!File.Exists(textcsvpath))
{
    File.WriteAllText(textcsvpath, textheader);
}
File.AppendAllText(textcsvpath, tab.ToString());

添加新文件时,您需要采取一些措施来确定新文件名。

答案 2 :(得分:0)

我会做这样的事情:

const int limit = 500;
int iteration = 0;
string textHeader = "Vendor\tDate\tInvoice\tPO\tTax\tTotal\tAcount\tType\tJobs\tClass" + Environment.NewLine;

while(iteration * limit < textLinesToAdd.Count())
{
  string fullPath = Path.Combine(filePath, $"{fileName}.{iteration}", extension);
  IEnumerable<string> linesToAdd = textLinesToAdd.Skip(iteration++ * limit).Take(limit);
  File.Create(fullPath);
  File.WriteAllText(fullPath, textHeader);
  File.AppendAllLines(fullPath, linesToAdd);
}

将该文件名定义为foo,并将扩展名定义为bar,您将获得一个名为foo.0.barfoo.1.barfoo.2.bar和等等。

答案 3 :(得分:0)

我假设我们要创建一个具有指定名称的文件,然后在该名称和扩展名之间放置一些整数,每次创建新文件时该整数都会递增。

执行此操作的一种方法是拥有一个方法,该方法采用filePath字符串,要写入的行列表,标题字符串以及每个文件允许的最大行数。然后它可以解析文件路径的目录,寻找与文件名相关的模式。

它将根据目录的内容以及与我们的模式匹配的最后一个文件中的行数来确定最新的文件名,然后写入该文件直到文件满,然后继续创建新文件文件,直到所有行都写完。

这是一个可以做到这一点的示例类,我在其中添加了一些辅助方法来获取文件的编号,在名称中递增该编号,从目录中获取最新的文件以及向该文件中写入行。它还实现了IComparer<string>,以便我们可以将其传递给OrderByDescending,以轻松地对我们感兴趣的文件进行排序。

public class FileWriterHelper : IComparer<string>
{
    public int Compare(string x, string y)
    {
        // Compare null
        if (x == null) return y == null ? 0 : 1;
        if (y == null) return -1;

        // Compare count of parts split on '.'
        var xParts = x.Split('.');
        var yParts = y.Split('.');
        if (xParts.Length < 3) return yParts.Length < 3 ? 0 : -1;
        if (yParts.Length < 3) return 1;

        // Compare numeric portion
        int xNum, yNum;
        if (int.TryParse(xParts[1], out xNum) &&
            int.TryParse(yParts[1], out yNum))
        {
            return xNum.CompareTo(yNum);
        }

        // Unknown values
        return string.Compare(x, y, StringComparison.Ordinal);
    }

    private static int? GetFileNumber(string fileName)
    {
        if (string.IsNullOrWhiteSpace(fileName)) return null;
        var fileParts = fileName.Split('.');
        int fileNum;
        if (fileParts.Length < 3 || !int.TryParse(fileParts[1], out fileNum)) return null;
        return fileNum;
    }

    private static string IncrementNumber(string fileName)
    {
        var number = GetFileNumber(fileName).GetValueOrDefault() + 1;
        var fileParts = fileName.Split('.');
        return $"{fileParts[0]}.{number}.{fileParts[fileParts.Length - 1]}";
    }

    private static string GetLatestFile(string filePath, int maxLines)
    {
        var fileDir = Path.GetDirectoryName(filePath);
        var fileName = Path.GetFileNameWithoutExtension(filePath);
        var fileExt = Path.GetExtension(filePath);

        var latest = Directory.GetFiles(fileDir, $"{fileName}*{fileExt}")
            .OrderByDescending(f => f, new FileWriterHelper())
            .FirstOrDefault() ?? filePath;

        return File.Exists(latest) && File.ReadAllLines(latest).Length >= maxLines
            ? Path.Combine(fileDir, IncrementNumber(Path.GetFileName(latest)))
            : latest;
    }

    public static void WriteLinesToFile(string filePath, string header, 
        List<string> lines, int maxFileLines)
    {
        while ((lines?.Count ?? 0) > 0 && maxFileLines > 0)
        {
            var latestFile = GetLatestFile(filePath, maxFileLines);
            if (!File.Exists(latestFile)) File.CreateText(latestFile).Close();
            var lineCount = File.ReadAllLines(latestFile).Length;

            if (lineCount == 0 && header != null)
            {
                File.WriteAllText(latestFile, string.Concat(header, Environment.NewLine));
                lineCount = 1;
            }

            var numLinesToWrite = maxFileLines - lineCount;
            File.AppendAllLines(latestFile, lines.Take(numLinesToWrite));

            lines = lines.Skip(numLinesToWrite).ToList();
        }
    }
}

这有点工作,但是现在使用起来非常简单:

private static void Main()
{
    // Generate 5000 lines to write
    var fileLines = Enumerable.Range(0, 5000).Select(i => $"Line number {i}").ToList();

    // File path with base file name
    var filePath = @"f:\public\temp\temp.csv";

    // This should create 10 files
    FileWriterHelper.WriteLinesToFile(filePath, 
        "HEADER: This should be the first line in each file.", fileLines, 500);

    GetKeyFromUser("\nDone! Press any key to exit...");
}

如果运行一次,它将创建10个文件(由于我们正在生成的行数以及我们指定的每个文件的最大行数)。如果再次运行它,它将创建10个以上的文件,因为我们使用相同的路径和文件名模式,它会识别该位置中的先前文件。

我确定它可以使用一些工作,但希望这是一个开始!