2013-10-04 88 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

2回、線の数を取得するために1回、分割するために1回ループする必要があります。または、線の数を推測してそのように分割することもできます。 –

+0

@ kw4ntaなぜ地球上であなたはラインを保存したいでしょうか? 1)OPは、すべての行を格納することはオプションではない、2)行を別のファイルに直接書くことができるとすれば... –

答えて

11

ファイルは非常に大きく、分割ファイルすることができますので、それ自体がaswell大きくなる可能性がある:

例:

ソースファイルサイズ:5ギガバイト

のNumスプリット: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にパディングしてファイルサイズを1レコードサイズに分割して分割します。また、それぞれの行を読むことはMQ上に送られて挿入されるので、非同期になります。とにかくあなたの魂は良いです。 –

0

エントリ数をカウントするカウンタがあります。たとえば、1行に1つのエントリがあるとします。

step1:最初に新しいサブファイルを作成し、カウンタ= 0を設定します。

STEP2:カウンターはあなたがサブファイルに各サブファイル、バッファのフラッシュ内容に書きたいエントリの数に上限に達する:インクリメントカウンタあなたは

STEP3をバッファリングするために、ソースファイルから各エントリを読んで。サブファイルに

STEP4を閉じる:ジャンプをSTEP1にあなたがファイルを使用して二回ループする必要はありません

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

完全なJavaコード:

サンプルスプリットやブロックに参加し、以下のようなものでした。

+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のレコード/行のファイルをテストしました。 1ファイルにつき1Lラインの隙間にファイルを分割するのに約10秒かかります。 –

関連する問題