2013-10-04 9 views
9

Mam plik, który chciałbym przeczytać w Javie i podzielić ten plik na pliki wyjściowe n (dane wejściowe użytkownika). Oto w jaki sposób odczytać pliku:Java - Odczytaj plik i podziel na kilka plików

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

Jak mogę podzielić plik - file.csv do n plików?

Uwaga: Ponieważ liczba wpisów w pliku jest rzędu 100 tys., Nie można zapisać zawartości pliku w postaci tablicy, a następnie podzielić i zapisać w wielu plikach.

+0

w pętli while, po prostu zbierz jak najwięcej linii, jak chcesz, do String lub StringBuilder i zapisz je do oddzielnych plików. Nie można wcześniej znać liczby plików, może być lepiej zdefiniować maksymalną liczbę wierszy w pliku. –

+0

Musisz albo wykonać pętlę dwa razy, raz, aby uzyskać liczbę linii i raz podzielić. Można też domyślić się liczby linii i podzielić w ten sposób. –

+0

@ kw4nta, dlaczego na ziemi chcesz ststore_ linii. 1) OP mówi, że przechowywanie wszystkich linii nie jest opcją, 2) biorąc pod uwagę, że możesz zapisać linie bezpośrednio do innego pliku ... –

Odpowiedz

11

Ponieważ plik może być bardzo duży, dzielenia plików mogłaby sama aswell być duże:

Przykład:

Źródło Rozmiar pliku: 5GB

Num Dzieli: 5: Destination

Rozmiar pliku: 1 GB każdy (5 plików)

Nie da się odczytać tego dużego podzielonego kawałka za jednym razem, nawet jeśli mamy takie wspomnienie. Zasadniczo dla każdego podziału możemy odczytać rozmiar poprawki byte-array, który, jak wiemy, powinien być wykonalny pod względem wydajności i pamięci.

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<numReads; i++) { 
        readWrite(raf, bw, maxReadBufferSize); 
       } 
       if(numRemainingRead > 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); 
     } 
    } 
+5

Cóż, może podzielić linię w połowie i ma to znaczenie dla pliku csv –

+0

Czy istnieje sposób przezwyciężyć to? aby nie dzieliła linii środkowej? – Julian

+0

W mojej firmie mamy stały rozmiar rekordu dla każdej kolumny i wprowadzamy dopełnienie do pliku CSV, więc dzielimy rozmiar pliku na jeden rozmiar rekordu, a następnie dzielimy. także Podczas czytania każda linia jest wysyłana na MQ do wstawienia, aby była asynchroniczna. W każdym razie twoja dusza jest dobra. –

0

Mieć licznik do zliczania braków wpisów. Powiedzmy jeden wpis na wiersz.

step1: Początkowo utwórz nowy fragment, ustaw counter = 0;

step2: licznik przyrost jak można przeczytać każdy wpis z pliku źródłowego do bufora

step3: gdy licznik osiągnie limit na liczbę wpisów, które chcesz napisać w każdym pliku sub, przemywać zawartość bufora do podtekstu. zamknąć podtekstu

Krok 4: skok krok1 aż masz dane w pliku źródłowego do odczytu z

0

Nie ma potrzeby do pętli dwukrotnie przez plik. Można oszacować rozmiar każdej porcji jako rozmiar pliku źródłowego podzielony przez liczbę potrzebnych porcji. Wtedy przestajesz wypełniać każdą komórkę danymi, ponieważ ich rozmiar przekracza szacunkową wartość.

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

} 

} 
+1

To nie robi tego, co chciał OP (ustawiona liczba plików), ale robi to, co chcę (ustawioną liczbę linii). Dobry kod! Zmodyfikowano jako funkcję przyjmującą nazwę pliku i dynamicznie nazywane utworzone pliki. –

+0

C & P z http://javaprogramming.language-tutorial.com/2012/10/split-huge-files-into-small-text-files.html? (Wpis na blogu pochodzi z 2012 r.) – bish

2

Choć jego stare pytanie, ale dla odniesienia Jestem wymieniając się kod, który użyłem do dzielenia dużych plików na dowolnych rozmiarach i współpracuje z dowolne wersje Java powyżej 1.4.

Splitu próbki i Dołącz bloki były jak poniżej:

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

kodu Kompletna java dostępnych tutaj w File Split in Java Program link.

+1

Podczas gdy ten link może odpowiedzieć na pytanie, lepiej umieścić tutaj istotne części odpowiedzi i podać link do odsyłacza. Odpowiedzi dotyczące linków mogą stać się nieprawidłowe, jeśli strona z linkami się zmieni. - [Z recenzji] (/ opinia/niskiej jakości-posty/12423371) – CubeJockey

+1

Dzięki, Zaktualizowano komentarz. – user1472187

0

Oto jeden, który zadziałał dla mnie i użyłem go do podzielenia pliku 10GB. umożliwia także dodanie nagłówka i stopki.bardzo przydatne przy dzieleniu formatu opartego na dokumencie, takiego jak XML i JSON, ponieważ musisz dodać opakowanie dokumentu w nowych podzielonych plikach.

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"); 
    } 
} 
0

Poniższy kod służy do podziału dużego pliku na małe pliki z mniejszymi liniami.

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

Kod, który napisałem powyżej działa i przetestowałem dla pliku z 40L rekordów/linii. Potrzeba około 10 sekund, aby podzielić plik na linie 1L na plik. –

Powiązane problemy