如何迭代数据并在每第n个条目创建一个新的文本文件

问题描述 投票:-1回答:4

我正在制作一个需要添加到.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);
c#
4个回答
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

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());

在添加新文件时,您需要执行一些操作来确定新文件名。


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等文件。


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个,因为我们使用相同的路径和文件名模式,它会识别该位置中的先前文件。

我相信它可以使用一些工作,但希望它是一个开始!

© www.soinside.com 2019 - 2024. All rights reserved.