Java: archivo de lectura y división en varios archivos

Tengo un archivo que me gustaría leer en Java y dividir este archivo en n (archivos de entrada de usuario). Así es como leo el archivo:

 int n = 4; BufferedReader br = new BufferedReader(new FileReader("file.csv")); try { String line = br.readLine(); while (line != null) { line = br.readLine(); } } finally { br.close(); } 

¿Cómo divido el archivo – file.csv en n archivos?

Nota: como el número de entradas en el archivo es del orden de 100k, no puedo almacenar el contenido del archivo en una matriz y luego dividirlo y guardarlo en varios archivos.

Dado que el archivo puede ser muy grande, los archivos divididos también podrían ser grandes:

Ejemplo:

Tamaño del archivo de origen: 5GB

Num Splits: 5: Destino

Tamaño de archivo: 1GB cada uno (5 archivos)

No hay forma de leer este gran fragmento dividido de una vez, incluso si tenemos ese tipo de memoria. Básicamente para cada división, podemos leer una byte-array tamaño de corrección que sabemos que debería ser factible en términos de rendimiento y memoria.

NumSplits: 10 MaxReadBytes: 8KB

 public static void main(String[] args) throws Exception { RandomAccessFile raf = new RandomAccessFile("test.csv", "r"); long numSplits = 10; //from user input, extract it from args long sourceSize = raf.length(); long bytesPerSplit = sourceSize/numSplits ; long remainingBytes = sourceSize % numSplits; int maxReadBufferSize = 8 * 1024; //8KB for(int destIx=1; destIx <= numSplits; destIx++) { BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream("split."+destIx)); if(bytesPerSplit > maxReadBufferSize) { long numReads = bytesPerSplit/maxReadBufferSize; long numRemainingRead = bytesPerSplit % maxReadBufferSize; for(int i=0; i 0) { readWrite(raf, bw, numRemainingRead); } }else { readWrite(raf, bw, bytesPerSplit); } bw.close(); } if(remainingBytes > 0) { BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream("split."+(numSplits+1))); readWrite(raf, bw, remainingBytes); bw.close(); } raf.close(); } static void readWrite(RandomAccessFile raf, BufferedOutputStream bw, long numBytes) throws IOException { byte[] buf = new byte[(int) numBytes]; int val = raf.read(buf); if(val != -1) { bw.write(buf); } } 
 import java.io.*; import java.util.Scanner; public class split { public static void main(String args[]) { try{ // Reading file and getting no. of files to be generated String inputfile = "C:/test.txt"; // Source File Name. double nol = 2000.0; // No. of lines to be split and saved in each output file. File file = new File(inputfile); Scanner scanner = new Scanner(file); int count = 0; while (scanner.hasNextLine()) { scanner.nextLine(); count++; } System.out.println("Lines in the file: " + count); // Displays no. of lines in the input file. double temp = (count/nol); int temp1=(int)temp; int nof=0; if(temp1==temp) { nof=temp1; } else { nof=temp1+1; } System.out.println("No. of files to be generated :"+nof); // Displays no. of files to be generated. //--------------------------------------------------------------------------------------------------------- // Actual splitting of file into smaller files FileInputStream fstream = new FileInputStream(inputfile); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String strLine; for (int j=1;j<=nof;j++) { FileWriter fstream1 = new FileWriter("C:/New Folder/File"+j+".txt"); // Destination File Location BufferedWriter out = new BufferedWriter(fstream1); for (int i=1;i<=nol;i++) { strLine = br.readLine(); if (strLine!= null) { out.write(strLine); if(i!=nol) { out.newLine(); } } } out.close(); } in.close(); }catch (Exception e) { System.err.println("Error: " + e.getMessage()); } } } 

Aunque es una vieja pregunta, pero como referencia, estoy enumerando el código que utilicé para dividir archivos grandes en cualquier tamaño y funciona con cualquier versión de Java por encima de 1.4.

Los bloques Sample Split and Join fueron como a continuación:

 public void join(String FilePath) { long leninfile = 0, leng = 0; int count = 1, data = 0; try { File filename = new File(FilePath); //RandomAccessFile outfile = new RandomAccessFile(filename,"rw"); OutputStream outfile = new BufferedOutputStream(new FileOutputStream(filename)); while (true) { filename = new File(FilePath + count + ".sp"); if (filename.exists()) { //RandomAccessFile infile = new RandomAccessFile(filename,"r"); InputStream infile = new BufferedInputStream(new FileInputStream(filename)); data = infile.read(); while (data != -1) { outfile.write(data); data = infile.read(); } leng++; infile.close(); count++; } else { break; } } outfile.close(); } catch (Exception e) { e.printStackTrace(); } } public void split(String FilePath, long splitlen) { long leninfile = 0, leng = 0; int count = 1, data; try { File filename = new File(FilePath); //RandomAccessFile infile = new RandomAccessFile(filename, "r"); InputStream infile = new BufferedInputStream(new FileInputStream(filename)); data = infile.read(); while (data != -1) { filename = new File(FilePath + count + ".sp"); //RandomAccessFile outfile = new RandomAccessFile(filename, "rw"); OutputStream outfile = new BufferedOutputStream(new FileOutputStream(filename)); while (data != -1 && leng < splitlen) { outfile.write(data); leng++; data = infile.read(); } leninfile += leng; leng = 0; outfile.close(); count++; } } catch (Exception e) { e.printStackTrace(); } } 

El código de Java completo está disponible aquí en la división de archivos en el enlace del progtwig Java .

Tener un contador para contar no de entradas. Digamos una entrada por línea.

paso1: Inicialmente crea un nuevo subarchivo, establece el contador = 0;

paso2: incrementa el contador a medida que lees cada entrada del archivo fuente al búfer

paso 3: cuando el contador alcanza el límite de la cantidad de entradas que desea escribir en cada archivo secundario, descargue los contenidos del búfer al subarchivo. cerrar el subarchivo

paso4: salta al paso 1 hasta que tengas datos en el archivo fuente para leerlos

No es necesario pasar dos veces por el archivo. Podría estimar el tamaño de cada fragmento como el tamaño del archivo de origen dividido por la cantidad de fragmentos necesarios. Luego dejas de llenar cada caché con datos ya que su tamaño excede el estimado.

Aquí hay uno que funcionó para mí y lo usé para dividir archivos de 10GB. también le permite agregar un encabezado y un pie de página. muy útil cuando se divide el formato basado en documentos, como XML y JSON, porque necesita agregar el contenedor de documentos en los nuevos archivos divididos.

 import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; public class FileSpliter { public static void main(String[] args) throws IOException { splitTextFiles("D:\\xref.csx", 750000, "", "", null); } public static void splitTextFiles(String fileName, int maxRows, String header, String footer, String targetDir) throws IOException { File bigFile = new File(fileName); int i = 1; String ext = fileName.substring(fileName.lastIndexOf(".")); String fileNoExt = bigFile.getName().replace(ext, ""); File newDir = null; if(targetDir != null) { newDir = new File(targetDir); } else { newDir = new File(bigFile.getParent() + "\\" + fileNoExt + "_split"); } newDir.mkdirs(); try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName))) { String line = null; int lineNum = 1; Path splitFile = Paths.get(newDir.getPath() + "\\" + fileNoExt + "_" + String.format("%02d", i) + ext); BufferedWriter writer = Files.newBufferedWriter(splitFile, StandardOpenOption.CREATE); while ((line = reader.readLine()) != null) { if(lineNum == 1) { System.out.print("new file created '" + splitFile.toString()); if(header != null && header.length() > 0) { writer.append(header); writer.newLine(); } } writer.append(line); if (lineNum >= maxRows) { if(footer != null && footer.length() > 0) { writer.newLine(); writer.append(footer); } writer.close(); System.out.println(", " + lineNum + " lines written to file"); lineNum = 1; i++; splitFile = Paths.get(newDir.getPath() + "\\" + fileNoExt + "_" + String.format("%02d", i) + ext); writer = Files.newBufferedWriter(splitFile, StandardOpenOption.CREATE); } else { writer.newLine(); lineNum++; } } if(lineNum <= maxRows) // early exit { if(footer != null && footer.length() > 0) { writer.newLine(); lineNum++; writer.append(footer); } } writer.close(); System.out.println(", " + lineNum + " lines written to file"); } System.out.println("file '" + bigFile.getName() + "' split into " + i + " files"); } } 

A continuación se usa el código para dividir un archivo grande en pequeños archivos con líneas menores.

  long linesWritten = 0; int count = 1; try { File inputFile = new File(inputFilePath); InputStream inputFileStream = new BufferedInputStream(new FileInputStream(inputFile)); BufferedReader reader = new BufferedReader(new InputStreamReader(inputFileStream)); String line = reader.readLine(); String fileName = inputFile.getName(); String outfileName = outputFolderPath + "\\" + fileName; while (line != null) { File outFile = new File(outfileName + "_" + count + ".split"); Writer writer = new OutputStreamWriter(new FileOutputStream(outFile)); while (line != null && linesWritten < linesPerSplit) { writer.write(line); line = reader.readLine(); linesWritten++; } writer.close(); linesWritten = 0;//next file count++;//nect file count } reader.close(); } catch (Exception e) { e.printStackTrace(); }