web-dev-qa-db-ja.com

コマンドラインを使用してテキストファイルを小さな複数のテキストファイルに分割する

私は約100,000行のテキストファイルを複数持っていますが、それらをそれぞれ5000行の小さなテキストファイルに分割したいのです。

私は使った:

split -l 5000 filename.txt

それはファイルを作成します。

xaa
xab
aac
xad
xbe
aaf

拡張子のないファイル私はそれらを以下のように呼びたいだけです。

file01.txt
file02.txt
file03.txt
file04.txt

それが不可能であれば、私は単にそれらが ".txt"拡張子を持つようにしたい。

60
ashleybee97

私はこの質問がずっと前にされたことを知っています、しかし私は誰も最も直接的なunix答えを与えなかったことに驚きます:

split -l 5000 -d --additional-suffix=.txt $FileName file
  • -l 5000:ファイルをそれぞれ5,000行のファイルに分割します。
  • -d:数字の接尾辞これにより、デフォルトでaaからzzの代わりに00から99に接尾辞が付けられます。
  • --additional-suffix:接尾辞、ここでは拡張子を指定できます
  • $FileName:分割するファイルの名前.
  • file:結果のファイルに追加する接頭辞。

いつものように、詳細についてはman splitをチェックしてください。

Macの場合、デフォルトバージョンのsplitは明らかに見捨てられています。次のコマンドを使用してGNUバージョンをインストールできます。 ( より多くのGNU utilsについてはこの質問を参照してください

brew install coreutils

そして、splitgsplitに置き換えることで上記のコマンドを実行できます。詳細はman gsplitを調べてください。

64
ursan

これがC#の例です(これが私が探していたものです)。ファイルを見るには、23 GBのcsvファイルを約1億7,500万行で分割する必要がありました。私はそれをそれぞれ100万行のファイルに分割しました。このコードは私のマシンで約5分でそれをしました:

var list = new List<string>();
var fileSuffix = 0;

using (var file = File.OpenRead(@"D:\Temp\file.csv"))
using (var reader = new StreamReader(file))
{
    while (!reader.EndOfStream)
    {
        list.Add(reader.ReadLine());

        if (list.Count >= 1000000)
        {
            File.WriteAllLines(@"D:\Temp\split" + (++fileSuffix) + ".csv", list);
            list = new List<string>();
        }
    }
}

File.WriteAllLines(@"D:\Temp\split" + (++fileSuffix) + ".csv", list);
19
Alex
@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET /a fcount=100
SET /a llimit=5000
SET /a lcount=%llimit%
FOR /f "usebackqdelims=" %%a IN ("%sourcedir%\q25249516.txt") DO (
 CALL :select
 FOR /f "tokens=1*delims==" %%b IN ('set dfile') DO IF /i "%%b"=="dfile" >>"%%c" ECHO(%%a
)
GOTO :EOF
:select
SET /a lcount+=1
IF %lcount% lss %llimit% GOTO :EOF
SET /a lcount=0
SET /a fcount+=1
SET "dfile=%sourcedir%\file%fcount:~-2%.txt"
GOTO :EOF

これは、タスクを実行するネイティブのWindowsバッチです。

今では、高速になるとは言いません(5Klineの各出力ファイルで2分未満)、または文字の感度をバッチ処理することはできません。本当にターゲットデータの特性に依存します。

テストには、100K行のデータを含むq25249516.txtという名前のファイルを使用しました。


改訂版のより速いバージョン

REM

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET /a fcount=199
SET /a llimit=5000
SET /a lcount=%llimit%
FOR /f "usebackqdelims=" %%a IN ("%sourcedir%\q25249516.txt") DO (
 CALL :select
 >>"%sourcedir%\file$$.txt" ECHO(%%a
)
SET /a lcount=%llimit%
:select
SET /a lcount+=1
IF %lcount% lss %llimit% GOTO :EOF
SET /a lcount=0
SET /a fcount+=1
MOVE /y "%sourcedir%\file$$.txt" "%sourcedir%\file%fcount:~-2%.txt" >NUL 2>nul
GOTO :EOF

テストにはllimitの50000を使用したことに注意してください。 llimit * 100がファイルの行数よりも大きい場合は、初期のファイル番号を上書きします(fcount1999に設定し、ファイル名変更行で~3の代わりに~2を使用してください)。

15
Magoo

あなたはおそらくawkでこのようなことをすることができます

awk '{outfile=sprintf("file%02d.txt",NR/5000+1);print > outfile}' yourfile

基本的には、レコード番号(NR)を取り、5000で割って1を加え、その整数を取り、2桁にゼロを埋め込んで、出力ファイルの名前を計算します。

デフォルトでは、awkは、何も指定しないと入力レコード全体を印刷します。そのため、print > outfileは入力レコード全体を出力ファイルに書き込みます。

あなたがWindows上で動いているとき、それはそれが好きではないので、あなたは一重引用符を使うことができません。このスクリプトをファイルに入れてから、awkにそのファイルを使用するように指示する必要があると思います。

awk -f script.awk yourfile

そしてscript.awkはこのようなスクリプトを含みます:

{outfile=sprintf("file%02d.txt",NR/5000+1);print > outfile}

または、これを実行すればうまくいくかもしれません。

awk "{outfile=sprintf(\"file%02d.txt\",NR/5000+1);print > outfile}" yourfile
8
Mark Setchell

構文は次のようになります。

$ split [OPTION] [INPUT [PREFIX]] 

プレフィックスはPREFIXaa、PREFIXab、...です。

適切なものを使用するだけで完了です。または名前の変更にはmvを使用してください。私は$ mv * *.txtはうまくいくはずだと思いますが、最初に小規模でテストします。

:)

7
Ravi

この「ファイルスプリッタ」Windowsコマンドラインプログラムはうまく機能します。 https://github.com/dubasdey/File-Splitter

それはオープンソースで、シンプルで、文書化され、証明され、そして私のために働きました。

例:

fsplit -split 50 mb mylargefile.txt
5
Fabian Kessler

私の要求は少し違いました。 1行が1レコードのデータであるComma DelimitedとTab Delimited ASCIIファイルでよく作業します。そしてそれらは本当に大きいので、(ヘッダ行を保存しながら)それらを管理しやすい部分に分割する必要があります。

それで、私は私の古典的なVBScriptメソッドに戻って、そしてどんなWindowsコンピュータでも実行できる小さい.vbsスクリプトを一緒にまとめました(それは、Windows上のWScript.exeスクリプトホストエンジンによって自動的に実行されます)。

このメソッドの利点は、テキストストリームを使用しているため、基になるデータがメモリに読み込まれないことです(少なくとも、一度にすべてが読み込まれることはありません)。その結果、これは非常に高速であり、実行にはそれほど多くのメモリーを必要としません。私のi7でこのスクリプトを使って分割したばかりのテストファイルは、約1GBのファイルサイズで、約1,200万行のテストがあり、25個のパートファイル(それぞれ約500k行)が作成されました。どの時点でも3 MB以上のメモリを使用しないでください。

ここでの注意点は、Text Streamオブジェクトは一度に1行ずつ処理するために "ReadLine"関数を使用するため、 "lines"を持つテキストファイル(各レコードはCRLFで区切られていることを意味します)に依存していることです。 TSVファイルやCSVファイルを使用しているのであれば、それは完璧です。

Option Explicit

Private Const INPUT_TEXT_FILE = "c:\bigtextfile.txt"  'The full path to the big file
Private Const REPEAT_HEADER_ROW = True                'Set to True to duplicate the header row in each part file
Private Const LINES_PER_PART = 500000                 'The number of lines per part file

Dim oFileSystem, oInputFile, oOutputFile, iOutputFile, iLineCounter, sHeaderLine, sLine, sFileExt, sStart

sStart = Now()

sFileExt = Right(INPUT_TEXT_FILE,Len(INPUT_TEXT_FILE)-InstrRev(INPUT_TEXT_FILE,".")+1)
iLineCounter = 0
iOutputFile = 1

Set oFileSystem = CreateObject("Scripting.FileSystemObject")
Set oInputFile = oFileSystem.OpenTextFile(INPUT_TEXT_FILE, 1, False)
Set oOutputFile = oFileSystem.OpenTextFile(Replace(INPUT_TEXT_FILE, sFileExt, "_" & iOutputFile & sFileExt), 2, True)

If REPEAT_HEADER_ROW Then
    iLineCounter = 1
    sHeaderLine = oInputFile.ReadLine()
    Call oOutputFile.WriteLine(sHeaderLine)
End If

Do While Not oInputFile.AtEndOfStream
    sLine = oInputFile.ReadLine()
    Call oOutputFile.WriteLine(sLine)
    iLineCounter = iLineCounter + 1
    If iLineCounter Mod LINES_PER_PART = 0 Then
        iOutputFile = iOutputFile + 1
        Call oOutputFile.Close()
        Set oOutputFile = oFileSystem.OpenTextFile(Replace(INPUT_TEXT_FILE, sFileExt, "_" & iOutputFile & sFileExt), 2, True)
        If REPEAT_HEADER_ROW Then
            Call oOutputFile.WriteLine(sHeaderLine)
        End If
    End If
Loop

Call oInputFile.Close()
Call oOutputFile.Close()
Set oFileSystem = Nothing

Call MsgBox("Done" & vbCrLf & "Lines Processed:" & iLineCounter & vbCrLf & "Part Files: " & iOutputFile & vbCrLf & "Start Time: " & sStart & vbCrLf & "Finish Time: " & Now())
5
Covenant

これはc#の中の1つで、大きなチャンクに分割してもメモリ不足にはなりません。私は95Mファイルを10M x行のファイルに分割する必要がありました。

var fileSuffix = 0;
int lines = 0;
Stream fstream = File.OpenWrite($"{filename}.{(++fileSuffix)}");
StreamWriter sw = new StreamWriter(fstream);

using (var file = File.OpenRead(filename))
using (var reader = new StreamReader(file))
{
    while (!reader.EndOfStream)
    {
        sw.WriteLine(reader.ReadLine());
        lines++;

        if (lines >= 10000000)
        {
              sw.Close();
              fstream.Close();
              lines = 0;
              fstream = File.OpenWrite($"{filename}.{(++fileSuffix)}");
              sw = new StreamWriter(fstream);
        }
    }
}

sw.Close();
fstream.Close();
2
Mobigital

私はこれのための簡単なプログラムを作成しました、そして、あなたの質問は私が解決を完成するのを助けました...私はもう一つの特徴といくつかの構成を加えました。数行ごとに特定の文字/文字列を追加したい場合(設定可能)。メモを確認してください。私はコードファイルを追加しました: https://github.com/mohitsharma779/FileSplit

0
User M