Java - dividindo o grande arquivo de texto SQL no delímetro usando o scanner (ourofMemoryError)

StackOverflow https://stackoverflow.com/questions/20353915

  •  25-08-2022
  •  | 
  •  

Pergunta

Estou tentando escrever um aplicativo que aceite um arquivo de texto SQL muito grande ~ 60 GB (257 milhões de linhas) e dividirá cada uma das instruções de cópia em arquivos de texto separados.

No entanto, o código que estou usando atualmente causa um outOfMemoryError devido às linhas que excedem o limite do buffer do scanner. A primeira declaração terá ~ 40 milhões de linhas de comprimento.

public static void readFileByDelimeter(String fileName, String requestType, String output) throws FileNotFoundException {

//creating file instance
File file = new File(fileName);

//create scanner instance
Scanner scanner = new Scanner(file, "latin1");

//set custom delimeter
scanner.useDelimeter("COPY");

int number = 0;
System.out.println("Running......");
while (scanner.hasNext()){
    String line = scanner.next();
    if (line.length() > 20) {
        //save statements to seperate SQL files
        PrintWriter out = new PrintWriter("statement" + number + ".sql");
        out.println("COPY" + line.trim());
        out.close();
        }
        number++;
    }

System.out.println("Completed");
}

Forneça recomendações sobre se esse é o método errado para executar isso ou alterações no método existente.

Obrigado

Foi útil?

Solução

Primeiro, por que você está criando ou algum outro processo está criando um arquivo de 60 GB! Talvez você precise dar uma olhada nesse processo para corrigir esse processo para gerar um arquivo de texto SQL menor em vez de criar um novo processo. No entanto, se isso for uma coisa única que você precisa fazer, isso pode estar bem, mas para abordar sua pergunta, eu usaria o BufferErader para ler e processar os registros, se for um arquivo grande como você indicava.

BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
   // process the line. and write into your output file and close the file.
   }
br.close();

Outras dicas

Eu pessoalmente: eu uso o BufferredReader em lugares do scanner. Ele também possui um método readline () conveniente e nunca tive problemas de desempenho com ele. A única coisa é que você precisa verificar manualmente se uma leitura de linha é uma que você deseja processar, mas isso geralmente é tão simples quanto aplicar os métodos da classe String.

Essa não é uma resposta para sua pergunta real, mas considero uma alternativa decente e fácil de usar.

Experimente algo assim (mas mais bonito):

Scanner sc = new Scanner(new BufferedReader(new FileReader(file)));

Isso decora a coisa toda com um leitor de buffers, o que significa que nem todo o conteúdo do arquivo será carregado na memória de uma só vez. Você pode usar o scanner da mesma maneira.

Tente usar um leitor de buffers. O uso direto do scanner com fluxos de arquivo ou arquivo bruto carrega os dados na memória e não o liberará no GC. A abordagem de apostas é usar o BufferredReader e ler uma linha de cada vez e fazer verificações manuais de string e divisão. Se feito corretamente dessa maneira, você pode dar ao GC oportunidade suficiente para recuperar a memória quando necessário

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top