How to group text file according to first line parameters in C#?

Asked

Viewed 634 times

0

I was able to join several text files of the same directory in a final text file, grouping the equal codes and adding their respective amounts, using the following code (credits to friend Vitor Mendes):

Dictionary<string, int> valores = new Dictionary<string, int>();

string diretorio = @"C:\teste";

string[] listaDeArquivos = Directory.GetFiles(diretorio);

if (listaDeArquivos.Length > 0)
{
    string caminhoArquivoDestino = @"C:\teste\saida.txt";

    FileStream arquivoDestino = File.Open(caminhoArquivoDestino, FileMode.OpenOrCreate);

    arquivoDestino.Close();

    List<string> linhasDestino = new List<string>();

    foreach (string caminhoArquivo in listaDeArquivos)
    {
         foreach (var linhaArquivoAtual in File.ReadAllLines(caminhoArquivo))
         {
            string id = linhaArquivoAtual.Substring(0, linhaArquivoAtual.Length - 3);
            string quantidade = linhaArquivoAtual.Substring(linhaArquivoAtual.Length - 3, 3);

            if (valores.ContainsKey(id)) 
            valores[id] = valores[id] + Convert.ToInt32(quantidade);
            else
            valores.Add(id, Convert.ToInt32(quantidade));           

         }
    }

    File.WriteAllLines(caminhoArquivoDestino, valores.Select(x => x.Key + x.Valeu.ToString("000")).ToArray());
}

The first line of home text file contains 2 identification parameters separated by a period. I will illustrate:

Conteúdo do Arq1.txt
000032;30032014
123456010
654321020

Conteúdo do Arq2.txt
000032;30032014
123456005
654321005

Conteúdo do Arq3.txt
000033;23052014
123456050
654321020

Conteúdo do Arq4.txt
000033;23052014
123456020
654321005

Conteúdo do Arq5.txt
000033;20052014
123456001
654321002

Conteúdo do Arq6.txt
000033;20052014
123456009
654321008

When grouping these files, the program should generate different final files according to the parameters of the first line. In these file examples, the end result will be the following files:

ArqFinal00003320052014.txt
123456010
654321010

ArqFinal00003323052014.txt
123456070
654321025

ArqFinal00003230032014.txt
123456015
654321025

That is, the program should group the files according to the first line, creating different final files.

  • The file should be with the first line parameter without the ';'?

  • could explain how the grouping by the parameters? as the system has q recognize that the file is part of a group or another

  • @Felipeavelar Yes, the final name yes. Until I do not know if it is possible to name some file using the character ";"

  • @Tafarelchicotti the grouping is by the first line. The program only sums the files q have the first line equal. So it generates several final files. In case of 3 arkivos, 2 with the first line equal and 1 not, 2 final arkivos will be generated: 1 with sum of arkivos with the first line equal and 1 with arkivo having the first line different.

2 answers

5

As an example in this answer, a dictionary is the solution for grouping items. In case you now have two levels of grouping, then the use of nested dictionaries is necessary. You have the dictionary with file names as key and the value is another dictionary with codes as key and quantities as value.

The code is far from great but it is tested and does what you want.

The comments were placed for didactic purposes and do not express the way I comment codes.

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

public class MergeFiles {
    public static void Main(string[] args) {
        var itens = new Dictionary<string, Dictionary<string, int>>(); //Cria a estrutura que permite chaves únicas do tipo string e valores associados do tipo int
        int resultado;
        foreach (var arquivo in Directory.GetFiles(@"C:\teste", "*.txt")) { //Pega todos os arquivos com extensão txt disponíveis no diretório
            var chaveArquivo = "";
            foreach (var linha in File.ReadAllLines(arquivo)){ //Lê todas as linhas individualmente de cada arquivo
                if (linha.Substring(6, 1)  == ";") { //Verifica se esta é a primeira linha
                   chaveArquivo = linha.Substring(0, 6) + linha.Substring(7, 8); //Pega os 6 primeiros caracteres e os 8 sequintes pulando o ;
                    if (!itens.ContainsKey(chaveArquivo)) { //verifica se não existe a chave com nome do arquivo
                        itens.Add(chaveArquivo, new Dictionary<string, int>()); //Adiciona uma nova chave ainda inexistente no dicionário
                    }
                } else {
                    var chave = linha.Substring(0, 6); //Pega os 6 primeiros caracteres
                    var valor = (int.TryParse(linha.Substring(6, 3), out resultado) ? resultado : 0); //Pega os 3 caracteres seguintes e converte para numérico
                    if (itens[chaveArquivo].ContainsKey(chave)) { //verifica se já existe a chave no dicionário
                        itens[chaveArquivo][chave] = itens[chaveArquivo][chave] + valor; //adiciona o valor obtido na linha à chave já existe no dicionário
                    } else {
                        itens[chaveArquivo].Add(chave, valor); //Adiciona uma nova chave ainda inexistente no dicionário
                    }
                }
            }
        }
        //Cria os arquivos agrupados adicionando todas as linhas do dicionário recriando a mesma estrutura anterior através do LINQ
        foreach(var arquivo in itens) {
            File.WriteAllLines(arquivo.Key + ".txt", arquivo.Value.Select(item => item.Key + item.Value.ToString("000")).ToArray());
        }
    }
}

I put in the Github for future reference.

  • Hello @bigown thanks so much for your attention. I will test your code, but from what I saw you changed the rest of the parameters not eh? The check of the first line is only to group text files that have the first line equal and thereby generate several different output arkives. My difficulty is in this. The rest of operation Jah is working properly.

  • 2

    If you already have something close to being ready, post this code. What you posted doesn’t even begin to do what you say you need. The above code has been tested with the data you have passed and produces exactly the results you presented. If that’s not what you need, then you need to explain it better. As far as I’m concerned, I’m giving you the ready-made solution in a well-organized code for the short time I’ve had to do it.

  • The code I posted works perfectly. What I need is just the differentiation of the files by reading the first line, that is, it is a function to add in the code that already works. I guess I didn’t need an answer so harsh, but I appreciate your time spent anyway.

  • 5

    If it works perfectly, you don’t need help. You can say that it is compiling, but it does absolutely nothing that you are saying it needs. If it does not do the exactly What you need, it doesn’t work perfectly. If you are not happy with the help you are getting here, you can also hire a professional.

  • Okay Bigown, thank you very much. =)

  • 1

    I don’t know if I didn’t understand something of the conversation here, but the code posted in the question is not even similar to what is necessary to solve the proposed problem, let alone with a "simple adaptation". To differentiate the files, I believe that the solution that was presented in the answer is fundamental to meet what was proposed in the question.

  • Hello @Bacco. The code I posted serves to join the files of the same folder. For this the code works correctly. Now what I need is a new function in it, so that it separates the text files according to the first line of the same before joining.

  • Well, I reread the comments and your previous questions here. Confirm for me then if this is it: what you want is not just a solution to the problem, but rather that someone take the code that you put in the question, and adapt for you, this would be it?

  • Hello @Bacco. I edited the code and put exactly what I use.

  • I would suggest you change the x.Valeu the last line of code you use exactly by x.Value, to avoid any possible problem.

  • @Bacco I gave the solution to the problem. I took the 6 example files that are in the question, I ran this code and generated 3 files exactly with the values that he presented in the question. The result is exactly what he says he wants. If the code doesn’t have exactly the construction he wants, it complicates it. To have a code written with every comma he thinks best, you have to hire someone to do it for him. If it refuses the code that gives the solution, I can do nothing else. Or is it that I am obliged to write the code in the style that each user wants?

  • @mustache up why I ended up doing this question, because the impression you gave me is that this is not just about solving the problem, but about using the code that the OP "sympathized with". Not that he doesn’t have the right to sympathize with some code, but it’s really hard to expect the site to work "à la carte". Perhaps the author of the other answer (the "thanks") wants to make the adjustment, who knows...

  • I appreciate your attention, guys. And I apologize for something I might have said that I didn’t like. I never wanted to be ungrateful at any point. Hugs!

Show 8 more comments

2

Using the question code, it should look like this:

static void Main(string[] args)
{
    string diretorio = @"C:\teste";

    String[] listaDeArquivos = Directory.GetFiles(diretorio);

    if (listaDeArquivos.Length > 0)
    {

        FileStream arquivoDestino = File.Open(caminhoArquivoDestino, FileMode.OpenOrCreate);
        arquivoDestino.Close();

        String[] linhasDestino;

        Dictionary<String, List<String>> out = new Dictionary<String, List<String>>();

        foreach (String caminhoArquivo in listaDeArquivos)
        {
            linhasDestino = File.ReadAllLines(caminhoArquivo);
            String name = linhasDestino[0].replace(';','');
            if (!out.ContainsKey(name))
            {
                out[name] = new List<String>();
            }
            for(int i = 1; i < linhasDestino.Length; i++)
            {
                out[name].Add(linhasDestino[i]);
            }
        }

        foreach(String key in out.Keys)
        {
            string caminhoArquivoDestino = @"C:\teste\"+key;
            File.WriteAllLines(caminhoArquivoDestino, out[key].ToArray());
        }
    }
}

I am without compiler here, but this should work. What is done is this:

  1. Opens the file;
  2. For each file opened, it sees if there is already an entry with that first line name of the file;
  3. Adds all lines (from the second) to an associated list that name;
  4. Then write all lines in files with the associated names.

Basically, the idea of the algorithm is this.

  • 1

    Thank you, Felipe. I will test. Basically, what the software has to do is to group/add the arkivos where the first line is equal.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.