Save.txt file

Asked

Viewed 1,393 times

3

I’m having difficulties in a code I’ve built. I can’t find the error. My problem is this:

I created a code that generates combinations of numbers and that should save these combinations in a file .txt. However, when I run the code, it sometimes saves only the last combination and sometimes saves nothing and sometimes saves some combinations, but not all that are generated by the code. The code I put together generates over a million combinations, is that why it’s giving trouble?

The code is as follows::

package gerasorte2;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Combinacoes {

    private int numeros[] = {3, 4, 5, 7, 8, 15, 16, 17, 18, 22, 24, 26, 28, 30, 32, 33, 34, 36, 37, 39, 41, 43, 44, 45, 47, 48, 50, 54, 56, 57, 58, 59, 60};
    private int quantidade = 6;
    private int resultado[] = new int[6];

    public int count = 0;

    public void busca(int inicio, int fim, int profundidade) throws IOException {

        FileWriter fw = new FileWriter("C:/Users/Usuario/Documents/Vander/mega.txt");
        BufferedWriter bw = new BufferedWriter(fw);

        if ((profundidade + 1) >= quantidade) {
            for (int x = inicio; x <= fim; x++) {

                resultado[profundidade] = numeros[x];

                count++;
                System.out.println(resultado[0] + " " + resultado[1] + " " + resultado[2] + " " + resultado[3] + " " + resultado[4] + " " + resultado[5] + "\n");
                bw.write(resultado[0] + " " + resultado[1] + " " + resultado[2] + " " + resultado[3] + " " + resultado[4] + " " + resultado[5] + "\n");
                bw.newLine();
                bw.flush();
            }
        } else {
            for (int x = inicio; x <= fim; x++) {

                resultado[profundidade] = numeros[x];

                busca(x + 1, fim + 1, profundidade + 1);

            }
        }
        bw.close();
        fw.close();

    }

    public static void main(String args[]) throws IOException {

        Combinacoes comb = new Combinacoes();

        comb.busca(0, (33 - 6), 0);

        System.out.println("Total de combinacoes: " + comb.count);

    }
}

1 answer

5


Your method busca is recursive and it performs IO operations. Let’s analyze what are the problems with IO:

  1. Each recursion of it opens the same file, performs operations on it and closes. Because the method is recursive, it means that you open millions of times the same file and will close it millions of times as well.

  2. To make matters worse, it also means that you open it several times and touch it while it is already open and being written independently in other parts of the program.

  3. The various writings that occur independently overwrite each other so that the final contents of the file will not be what you want. This lot of writing and rewriting occurring simultaneously generates a lot of confusion, because these writings are competing with each other in an unspecified way, which results in undefined behavior (Undefined behaviour) and makes the result in your file so strange and nondeterministic.

  4. Opening, writing and closing the same file millions of times is a very slow operation. Abusing bw.flush() only makes the situation even worse.

  5. I believe this is a very curious way to reduce the lifespan of your hard drive, while writing and overwriting millions of times the same file repeatedly in the same physical position of the disk in a short span of time. If done on a flash drive, it will be a good way to damage it permanently, since after a few thousand rewrites, it degrades and you will start to have defective areas on your flash drive.

Besides the IO issue, there are other things we can notice:

  1. count It’s a public attribute. I believe you must have read in a lot of places, explanations of why this is a bad idea and a bad programming practice.

  2. Its algorithm is fixed for a quantidade = 6. Changing this value will break the algorithm because the array size resultado is also fixed at 6 and the bw.write writes exactly 6 elements to the file.

  3. The (33 - 6) chapado in the code is something very boring to deal with. Chapado file name also.

  4. The variable quantidade may be replaced by resultado.length.

  5. You are abusing line breaks by concatenating the "\n". Remember that the System.out.println and the bw.newLine() They’re adding line breaks. So unless you really want to print the numbers only on the odd lines and leave the even lines blank, this one \n is something that is the most.

  6. It is more readable and recommended to declare arrays as int[] nomeDaVariavel instead of int nomeDaVariavel[]. The reason for this is that in the first form you have the type of the full variable followed by the name of the variable, which is the default form and which occurs in all other ways of declaring variables in Java. Whereas in the second form you have a part of the variable type, followed by the variable name, followed by the other part of the variable type, which is confusing, since the information about the variable type is fragmented into two distinct locations.

  7. Why use System.out.println if you’re already saving everything in a file? A lot of people don’t know this, but the System.out.println can be a very slow and heavy operation to use.

So, after fixing all these problems listed up there, here is the resulting code down there (only the file name was different on my machine, but I put the same file name of yours in the code that follows):

package gerasorte2;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Combinacoes {

    private static final class Buscador implements AutoCloseable {
        private final int[] numeros;
        private final int[] resultado;

        private int count = 0;

        private final FileWriter fw;
        private final BufferedWriter bw;
        private boolean fechado;

        private Buscador(int[] numeros, int quantidade, String arquivo) throws IOException {
            if (arquivo == null) throw new IllegalArgumentException("O arquivo não pode ser nulo.");
            if (numeros == null) throw new IllegalArgumentException("O conjunto de números não pode ser nulo.");
            if (numeros.length == 0) throw new IllegalArgumentException("O conjunto de números não pode ser vazio.");
            if (quantidade <= 0) throw new IllegalArgumentException("A quantidade de números a sortear deve ser maior que zero.");
            if (quantidade > numeros.length) throw new IllegalArgumentException("Não se pode sortear mais do que todos os números do conjunto.");
            this.resultado = new int[quantidade];
            this.numeros = numeros;
            this.fw = new FileWriter(arquivo);
            this.bw = new BufferedWriter(fw);
            this.fechado = false;
        }

        @Override
        public void close() throws IOException {
            fechado = true;
            bw.close();
            fw.close();
        }

        private int busca() throws IOException {
            busca(0, numeros.length - resultado.length, 0);
            return count;
        }

        private String arrayToString() {
            StringBuilder sb = new StringBuilder(3 * resultado.length);
            sb.append(resultado[0]);
            for (int i = 1; i < resultado.length; i++) {
                sb.append(" ").append(resultado[i]);
            }
            //sb.append("\n");
            return sb.toString();
        }

        private void busca(int inicio, int fim, int profundidade) throws IOException {
            if (fechado) throw new IOException();
            if (profundidade + 1 >= resultado.length) {
                for (int x = inicio; x <= fim; x++) {
                    resultado[profundidade] = numeros[x];
                    count++;
                    String s = arrayToString();
                    //System.out.println(s);
                    bw.write(s);
                    bw.newLine();
                    //bw.flush();
                }
            } else {
                for (int x = inicio; x <= fim; x++) {
                    resultado[profundidade] = numeros[x];
                    busca(x + 1, fim + 1, profundidade + 1);
                }
            }
        }
    }

    public static int busca(int[] numeros, int quantidade, String arquivo) throws IOException {
        try (Buscador comb = new Buscador(numeros, quantidade, arquivo)) {
            return comb.busca();
        }
    }

    public static void main(String[] args) throws IOException {
        int[] numeros = {3, 4, 5, 7, 8, 15, 16, 17, 18, 22, 24, 26, 28, 30, 32, 33, 34, 36, 37, 39, 41, 43, 44, 45, 47, 48, 50, 54, 56, 57, 58, 59, 60};
        int c = busca(numeros, 6, "C:/Users/Usuario/Documents/Vander/mega.txt");
        System.out.println("Total de combinações: " + c);
    }
}

I tested the code, and it worked perfectly. And it was fast too:

  • It took only 2 seconds to make all 1,107,568 combinations and save them in the file on my machine.

  • If you uncomment the line of System.out.println, It slows down a lot, and it takes between two minutes and two and a half minutes on my machine. However, this depends a lot on the type of console that is getting the output or where it is redirected to (I’ve circled it from inside the Netbeans IDE).

  • Its original version, besides generating the file wrongly and abusing the hard drive, should probably take about 15 minutes on my machine. I didn’t have the patience or the courage to carry it out.

Ah, and if you want to put the \n more or insist on using the flush to each line, just uncomment their lines. I do not recommend nor see need in either of the two however.

Browser other questions tagged

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