@presstencao/convert_file
Version:
Este pacote é utilizado para converter arquivos `.txt` para `.csv` e mover o arquivo convertido para um novo caminho. Ele possui funcionalidades para manipulação de arquivos em chunks, permitindo o processamento de grandes volumes de dados.
254 lines (219 loc) • 9.03 kB
JavaScript
const fs = require("fs");
const readline = require("readline");
const os = require("os");
const ProgressBar = require("progress");
/**
* Função para converter um arquivo `.txt` para um arquivo `.csv` e move-lo para um novo caminho.
*
* @param {Object} options - O objeto de opções.
* @param {string} options.path - O caminho do diretório onde o arquivo `.txt` está localizado.
* @param {string} options.file_name - O nome do arquivo `.txt` que deseja converter.
* @param {string} options.new_path - O caminho do diretório onde o arquivo `.csv` deve ser movido.
* @param {string} options.ext - A extensão do arquivo que deseja converter (padrão: `csv`).
* @param {Function} [options.callback] - A função de callback que será chamada após o término do processamento (opcional).
* @param {number} [options.chunk_size = 1000] - O tamanho do chunk que será processado por vez (padrão: 1000).
* @param {number} [options.pause_time = 400] - O tempo de pausa entre cada chunk (padrão: 400ms).
* @param {boolean} [options.header = false] - Indica se o arquivo tem um cabeçalho (padrão: false).
*
* @example
* const convert = require('@presstencao/convert_file');
* convert({ path: './', file_name: 'teste.txt', new_path: './newPath', callback: console.log });
*/
module.exports = async ({
path,
file_name,
new_path,
ext,
callback,
chunk_size = 1000,
pause_time = 400,
header = false,
}) => {
if (!path) {
throw new Error('path is required');
}
if (!file_name) {
throw new Error('file_name is required');
}
if (!new_path) {
throw new Error('new_path is required');
}
console.log("Início da função converter");
try {
console.log("Parâmetros recebidos:", {
path,
file_name,
new_path,
ext,
chunk_size,
pause_time,
header,
});
const temp_path = os.tmpdir();
const txt_path = path + "/" + file_name;
const txt_path_temp =
temp_path + "/" + file_name.split(".")[0] + "." + ext;
console.log("Caminhos:", { txt_path, txt_path_temp });
fs.mkdirSync(new_path, { recursive: true });
console.log("Diretório criado:", new_path);
try {
fs.unlinkSync(txt_path_temp);
console.log("Arquivo temporário deletado:", txt_path_temp);
} catch (err) {
if (err.code !== "ENOENT") {
console.error(
"Erro ao deletar arquivo temporário existente:",
err
);
}
}
const readStream = fs.createReadStream(txt_path, {
highWaterMark: 64 * 1024,
});
let lineCount = 0;
let processedLines = 0;
let delimiter = null;
let isFirstLine = true;
const lineCounter = readline.createInterface({
input: readStream,
crlfDelay: Infinity,
});
lineCounter.on("line", (line) => {
lineCount++;
if (delimiter === null) {
if (line.includes("\t")) {
delimiter = "\t";
} else if (line.includes(";")) {
delimiter = ";";
} else if (line.includes(" ")) {
delimiter = " ";
}
}
});
lineCounter.on("close", async () => {
console.log(
"Contagem de linhas concluída. Delimitador:",
delimiter
);
if (delimiter === null) {
delimiter = " ";
console.warn(
"Nenhum delimitador claro detectado. Usando espaço como padrão."
);
}
console.log(`Delimitador detectado: '${delimiter}'`);
console.log(
`Arquivo ${txt_path} tem ${fs.statSync(txt_path).size / (1024 * 1024)
}MB`
);
console.log(`Arquivo ${txt_path} tem ${lineCount} linhas.`);
const bar = new ProgressBar(
"[:bar] :percent - :etas - :current/:total - :rate - :elapseds",
{
complete: "=",
incomplete: " ",
width: 40,
total: lineCount,
}
);
const size = fs.statSync(txt_path).size;
const sizeMB = size / (1024 * 1024);
bar.interrupt(
`Tamanho do arquivo: ${sizeMB.toFixed(2)}MB - Faltam ${(
((sizeMB - processedLines / (1024 * 1024)) / sizeMB) *
100
).toFixed(2)}% para concluir`
);
const readStreamForProcessing = fs.createReadStream(txt_path, {
highWaterMark: 64 * 1024,
});
const rl = readline.createInterface({
input: readStreamForProcessing,
crlfDelay: Infinity,
});
let chunk = [];
rl.on("line", async (line) => {
line = line.replace(new RegExp(delimiter, "g"), ",").trim();
line = line.replace(/,\s*$/, "").replace(/\s*,/g, ",");
if (header && isFirstLine) {
fs.appendFile(txt_path_temp, line + "\n", (err) => {
if (err)
console.error(
"Erro ao escrever cabeçalho no arquivo temporário:",
err
);
});
isFirstLine = false;
} else {
chunk.push(line);
}
if (chunk.length >= chunk_size) {
const formattedChunk = chunk.join("\n") + "\n";
fs.appendFile(txt_path_temp, formattedChunk, (err) => {
if (err)
console.error(
"Erro ao escrever no arquivo temporário:",
err
);
});
processedLines += chunk.length;
bar.tick(chunk.length);
chunk = [];
rl.pause();
await new Promise((resolve) =>
setTimeout(resolve, pause_time)
);
rl.resume();
}
});
rl.on("close", async () => {
if (chunk.length > 0) {
const formattedChunk = chunk.join("\n") + "\n";
fs.appendFile(txt_path_temp, formattedChunk, (err) => {
if (err)
console.error(
"Erro ao escrever no arquivo temporário:",
err
);
});
processedLines += chunk.length;
bar.tick(chunk.length);
}
console.log("Processamento do arquivo concluído.");
console.log(
`Arquivo ${txt_path_temp} tem ${fs.statSync(txt_path_temp).size / (1024 * 1024)
}MB`
);
const readStreamTemp = fs.createReadStream(txt_path_temp);
const writeStreamNewPath = fs.createWriteStream(
new_path + "/" + file_name.split(".")[0] + "." + ext
);
readStreamTemp.pipe(writeStreamNewPath);
readStreamTemp.on("error", (err) => {
console.error("Erro ao ler arquivo temporário:", err);
});
writeStreamNewPath.on("error", (err) => {
console.error("Erro ao escrever novo arquivo:", err);
});
writeStreamNewPath.on("finish", () => {
console.log("Arquivo movido.");
});
readStreamTemp.on("close", () => {
fs.unlinkSync(txt_path_temp);
callback(new_path);
});
callback(new_path);
});
rl.on("error", (err) => {
console.error("Erro ao ler ou processar arquivo:", err);
});
});
lineCounter.on("error", (err) => {
console.error("Erro ao contar linhas:", err);
});
} catch (error) {
console.error("Erro na função converter:", error);
}
callback(new_path);
console.log("Fim da função converter");
};