How to group codes and add existing amounts to text files with C #?

2

I have several text files inside a directory. I need to do in C # and merge all the text files into a final text file, but handling the contents of them.

Example:

Arq1.txt
123456010
654321020

Arq2.txt
123456040
654321005

The first 6 characters are a code and the final 3 characters are the quantity. I need to merge the files in some way that a final file is generated by looking at the codes, without repeating them and adding up the quantities.

ArqFinal.txt
123456050
654321025

Sorry for not putting codes, but I really have no idea.

    
asked by anonymous 22.05.2014 / 18:25

4 answers

6

I've adapted the previous answer for this case. I did not think of all the possibilities. You have not given criteria for solving problems of file misrepresentation, whether to validate the codes, and what happens if the quantity does not contain a valid numeric value.

I assumed that it is implied that the values of the quantity are always integers and that an invalid value would be considered zero. I also considered that the minimum that a line should have to validate is the exact length of 9 characters.

I used an auxiliary data structure to put all codes into memory using unique keys and adding up the quantities in the existing codes.

I did a quick test and it is showing the expected result. The code certainly can be better organized.

Comments are being used for educational purposes only and do not reflect my coding style.

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

public class MergeFiles {
    public static void Main(string[] args) {
        var caminhoOrigem = @"C:\teste";
        var nomeArquivoCompleto = @"C:\teste\saida.txt";
        var itens = new 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(caminhoOrigem, "*.txt")) { //Pega todos os arquivos com extensão txt disponíveis no diretório
            if (arquivo != nomeArquivoCompleto) { //Não deixa processar o próprio arquivo que está sendo criado
                foreach (var linha in File.ReadAllLines(arquivo)) { //Lê todas as linhas individualmente de cada arquivo
                    if (linha.Length == 9) { //Garante que a linha tem 9 caracteres
                        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.ContainsKey(chave)) { //verifica se já existe a chave no dicionário
                            itens[chave] = itens[chave] + valor; //adiciona o valor obtido na linha à chave já existe no dicionário
                        } else {
                            itens.Add(chave, valor); //Adiciona uma nova chave ainda inexistente no dicionário
                        }
                    }
                }
            }
        }
        //Cria o arquivo destino adicionando todas as linhas do dicionário recriando a mesma estrutura anterior através do LINQ
        File.WriteAllLines(nomeArquivoCompleto, itens.Select(item => item.Key + item.Value.ToString("000")).ToArray());
    }
}

I placed it on GitHub for future reference .

    
22.05.2014 / 21:28
2

Certainly this thread is a continuation of this ( Merge multiple files text in only one? ), then I'll use the code posted by @reiksiel to complement the example:

Well, as you yourself said, the quantity is represented by the last 3 digits, so we can use a Dictionary where this ID would be the key and if there is already this ID in the dictionary you will add it up and then export it to the .txt, something like this:

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

I was not able to test this code because I'm without Visual Studio, but it would be something like this.

    
22.05.2014 / 19:23
2
string[] arrayFiles = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.txt");
string outputFile = Directory.GetCurrentDirectory() + @"\ArquivoSaida.txt";
Dictionary<string, int> values = new Dictionary<string, int>();

   if (File.Exists(outputFile))
   {
      Console.WriteLine("O arquivo de saída existe!");
      Console.ReadLine();
      Environment.Exit(0);
   }

   for (int i = 0; i < arrayFiles.Count(); i++)
   {
      foreach (string line in File.ReadAllLines(arrayFiles[i]))
      {
         string id  = Regex.Match(line, @"[0-9]...{3}").Value;
         string qtd = Regex.Match(line, @"[0-9]..\z{3}").Value;

      if (values.ContainsKey(id))
         values[id] = values[id] + Convert.ToInt32(qtd);
      else
         values.Add(id, Convert.ToInt32(qtd));  
       }
    }
    File.WriteAllLines(outputFile , values.Select(x => x.Key + x.Value).ToArray());
    Console.WriteLine("Procedimento realizado, Pressione alguma tecla para sair...");
    Console.ReadLine();

This will search for all text files in the current working directory, if the output file exists, the program will issue a message saying that the file exists and will terminate the program. Unlike the other great responses in which the String.Substring , this code addresses the use of regular expressions , simple yet functional expressions in the test I performed.

txtfile1.txt
   123456010
   654321020
txtfile2.txt
   123456040
   654321005
txtfile3.txt
   123456080
   654321007
ArquivoSaida.txt
   123456130
   65432132

Thanks @Bacco!

    
22.05.2014 / 22:00
1

Using FileHelpers this does not seem to be very complicated.

Class layout of records containing code and quantity:

public class Registro
{
    [FieldFixedLength(6)]
    public int Codigo {get; set; }

    [FieldFixedLength(3)]
    public int Quantidade {get; set; }
}

using FileHelpers;

// Realiza todo o processamento. Observe os métodos abaixo para entender o código.
public void CombinarRegistros(List<string> listaDeArquivos)
{
    var listaDeRegistros = new List<Registro>();

    foreach (var arquivo in listaDeArquivos)
    {
        listaDeArquivos.AddRange(ObtenhaRegistros(arquivo));
    }

    var registrosCombinados = CombineQuantidades(listaDeRegistros);

    EscrevaArquivoDosRegistrosCombinados("ArquivoFinal.txt", registrosCombinados);
}

// Lê os registros dos arquivos originais.
public List<Registro>() ObtenhaRegistros(string nomeDoArquivo)
{
    var engine = new MultiRecordEngine(typeof(Registro));

    var linhasDoArquivo = engine.ReadFile(nomeDoArquivo);

    var listaDeRegistros = new List<Registro>();

    foreach (var linha in linhasDoArquivo)
    {
        lista.Add((Registro)linha);
    }

    return listaDeRegistros;
}

// Combina a quantidade dos registros.
public List<Registro>() CombineQuantidades(List<Registro> registros)
{
    return registros.GroupBy(x => x.Codigo).Select(y => new Registro
    {
        Codigo = y.First().Codigo,
        Quantidade = y.Sum(z => z.Quantidade)
    }).ToList();
}

// Escreve os registros combinados somando a quantidade em um único arquivo.
public void EscrevaArquivoDosRegistrosCombinados(string nomeDoArquivoDeDestino, registros)
{
    MultiRecordEngine engine = new MultiRecordEngine(typeof(Registro));

    engine.AppendToFile(nomeDoArquivoDeDestino, registros);
}
    
16.07.2015 / 18:47