2013-10-04 2 views
9

Java에서 읽고 싶은 파일이 있고이 파일을 n (사용자 입력) 출력 파일로 나눕니다. 여기에 내가 파일을 읽는 방법은 다음과 같습니다Java - 파일 읽기 및 여러 파일로 분할

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

을 어떻게 파일 분할 할 - n 파일로 file.csv를?

주 - 파일의 항목 수가 100k가 넘기 때문에 파일 내용을 배열에 저장 한 다음 분할하여 여러 파일에 저장할 수 없습니다.

+0

while 루프에서 원하는만큼 많은 줄을 String 또는 StringBuilder에 수집하여 별도의 파일에 쓸 수 있습니다. 파일의 최대 줄 수를 정의하기 전에 미리 파일 수를 알 수는 없습니다. –

+0

회선 수를 얻으려면 한 번, 분할하려면 한 번 두 번 반복해야합니다. 또는 선의 수를 추측하고 그런 식으로 나눌 수 있습니다. –

+0

@ kw4nta 지구상에 왜 줄을 꾸미고 싶습니까? 1) OP는 모든 라인을 저장하는 것이 옵션이 아니라고 말합니다. 2) 라인을 다른 파일에 똑바로 작성할 수 있다고 가정하면 ... –

답변

11

파일이 매우 큰, 분할 파일 수 있기 때문에 그 자체가 aswell 큰 수 :

예 :

소스 파일 크기 : 5기가바이트

민 분할 : 5 : 대상

파일 크기 : 각 1GB (5 개 파일)

우리는 그런 메모리가 있더라도 한 번에이 큰 분할 청크를 읽을 방법이 없습니다. 기본적으로 각 분할마다 성능과 메모리면에서 실현 가능한 픽스 크기 byte-array을 읽을 수 있습니다.

NumSplits : 10 MaxReadBytes : 8킬로바이트

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

글쎄 중간 줄을 나눌 수 있으며 CSV 파일의 경우 중요합니다. –

+0

방법이 있습니까? 이것을 극복하기 위해서? 중간 선을 분할하지 않도록? – Julian

+0

우리 회사에서는 각 열의 레코드 크기가 고정되어 있고 CSV로 채워서 하나의 레코드 크기로 파일 크기를 나눈 다음 분할합니다. 또한 각 행을 읽는 동안 MQ에 보내져 비동기 적으로 삽입됩니다. 어쨌든 당신의 영혼은 좋습니다. –

0

항목 수를 세는 카운터가 있어야합니다. 한 줄에 하나의 항목을 말해 보겠습니다.

step1 : 초기에 새 서브 파일을 작성하고 카운터 = 0으로 설정하십시오. 카운터는 각 하위 파일에 기록 할 항목의 수에 한계에 도달 할 때, 버퍼의 내용을 플러쉬가 서브 파일을 :

2 단계 : 당신이

STEP3 버퍼 소스 파일에서 각 항목을 읽을 때 증가 카운터. 서브 파일을

STEP4을 닫습니다 점프를 1 단계로이 파일을 통해 두 번 반복 할 필요가 없습니다

0

에서 읽을 소스 파일에 데이터를 때까지. 소스 파일 크기를 필요한 청크 수로 나눈 값으로 각 청크의 크기를 예측할 수 있습니다. 그런 다음 크기가 예상보다 커지면서 각 덩어리에 데이터를 채우기 만하면됩니다.

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

이것은 OP가 원했던 것을하지 않고 (파일 수 설정), 원하는대로 (라인 수 설정)합니다. 좋은 코드! 파일 이름을 가져 와서 생성 된 파일의 이름을 동적으로 지정하는 함수로 수정했습니다. –

+0

C & P (http://javaprogramming.language-tutorial.com/2012/10/split-huge-files-into-small-text-files.html)? (블로그 항목은 2012 년부터입니다.) – bish

2

비록 자사의 오래된 질문이지만 참조 용 나는 내가 어떤 크기로 큰 파일을 분할하는 데 사용되는 코드를 나열하고 그것이 작동 1.4 이상의 모든 Java 버전. File Split in Java Program 링크에서 여기에 해당

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

완전한 자바 코드 :

샘플 분할 및 가입 블록은 다음과 같았다.

+1

이 링크가 질문에 대답 할 수 있지만 여기에 답의 핵심 부분을 포함하고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 유효하지 않게 될 수 있습니다. - [검토 중] (리뷰/저품절 포스트/12423371) – CubeJockey

+1

감사합니다. 코멘트를 업데이트했습니다. – user1472187

0

나를 위해 일한 것이고 10GB 파일을 나누는데 사용했습니다. 머리글과 바닥 글을 추가 할 수도 있습니다.새 분할 파일에 문서 래퍼를 추가해야하므로 XML 및 JSON과 같은 문서 기반 형식을 분할 할 때 매우 유용합니다.

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

큰 파일을 작은 파일로 분할하는 데 사용되는 코드는 다음과 같습니다.

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

위 코드는 작동 중이며 40L 레코드/줄의 파일을 테스트했습니다. 파일 당 1L 라인의 덩어리로 파일을 분할하는 데 약 10 초가 걸립니다. –