Diviser le fichier texte en plusieurs fichiers texte plus petits en utilisant la ligne de commande

j'ai plusieurs fichiers texte avec environ 100.000 lignes et je veux les diviser en petits fichiers texte de 5000 lignes chacun.

j'ai utilisé:

split -l 5000 filename.txt

qui crée des fichiers:

xaa
xab
aac
xad
xbe
aaf

fichiers sans extension. Je veux juste appeler quelque chose comme:

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

ou, si cela n'est pas possible, je veux juste qu'ils aient la ".txt " extension.

50
demandé sur ashleedawg 2014-08-11 21:57:07

9 réponses

je sais que la question a été posée il y a longtemps, mais je suis surpris que personne n'ait donné la réponse unix la plus simple:

split -l 5000 -d --additional-suffix=.txt $FileName file
  • -l 5000 : séparez le fichier en fichiers de 5 000 lignes chacun.
  • -d : suffixe numérique. Cela fera passer le suffixe de 00 à 99 par défaut au lieu de aa à zz.
  • --additional-suffix : permet de spécifier le suffixe, ici l'extension
  • $FileName : nom du fichier à diviser.
  • file : préfixe à ajouter aux fichiers résultants.

Comme toujours, consultez man split pour plus de détails.

Pour Mac, la version par défaut de split est apparemment de bêtise. Vous pouvez installer la version GNU en utilisant la commande suivante. ( voir cette question pour plus de GNU utils )

brew install coreutils

et ensuite vous pouvez exécuter la commande ci-dessus en remplaçant split par gsplit . Consultez man gsplit pour plus de détails.

45
répondu ursan 2018-01-17 02:41:31

Voici un exemple en C# (parce que c'est ce que je cherchais). J'avais besoin de partager un fichier csv de 23 Go avec environ 175 millions de lignes pour pouvoir regarder les fichiers. Je l'ai divisé en fichiers d'un million de lignes chacun. Ce code l'a fait en environ 5 minutes sur ma machine:

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);
17
répondu Alex 2016-07-28 09:48:24
@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

voici un lot de Windows natif qui devrait accomplir la tâche.

maintenant je ne vais pas dire que ce sera rapide (moins de 2 minutes pour chaque fichier de sortie 5Kline) ou qu'il sera immunisé contre les sensibilités de caractère de fournée. Vraiment dépend des caractéristiques de données cible.

j'ai utilisé un fichier nommé q25249516.txt contenant 100 lignes de données pour mes tests.


révisé version plus rapide

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

Notez que j'ai utilisé llimit de 50000 pour les tests. Va écraser les premiers numéros de fichier si llimit *100 est plus rapide que le nombre de lignes dans le fichier (guérir en mettant fcount à 1999 et utiliser ~3 à la place de ~2 dans le fichier-Ligne de renommage.)

15
répondu Magoo 2016-06-30 06:36:56

vous pouvez peut-être faire quelque chose comme ça avec awk

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

essentiellement, il calcule le nom du fichier de sortie en prenant le numéro d'enregistrement (NR) et en le divisant par 5000, en ajoutant 1, en prenant l'entier de cela et Zero-padding à 2 endroits.

par défaut, awk imprime l'enregistrement d'entrée entier lorsque vous ne spécifiez rien d'autre. Ainsi, print > outfile écrit l'enregistrement d'entrée entier dans le fichier de sortie.

comme vous exécutez sur Windows, vous ne pouvez pas utiliser des guillemets simples parce qu'il n'aime pas cela. Je pense que vous devez mettre le script dans un fichier et ensuite dire awk pour utiliser le fichier, quelque chose comme ça:

awk -f script.awk yourfile

et script.awk contiendra le script comme ceci:

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

Ou, il peut fonctionner si vous faites cela:

awk "{outfile=sprintf(\"file%02d.txt\",NR/5000+1);print > outfile}" yourfile
7
répondu Mark Setchell 2014-08-11 21:15:58

la syntaxe ressemble à:

$ split [OPTION] [INPUT [PREFIX]] 

où le préfixe est PREFIXaa, PREFIXab,...

il suffit d'utiliser un bon et vous êtes fait ou juste utiliser mv pour le renameing. Je pense $ mv * *.txt devrait fonctionner, mais d'abord tester sur une plus petite échelle.

:)

7
répondu Ravi 2016-01-25 16:45:27

mon exigence était un peu différente. Je travaille souvent avec des fichiers ASCII délimités par des virgules et des tabulations où une seule ligne est un enregistrement unique de données. Et ils sont vraiment grands, donc je dois les diviser en parties gérables (tout en préservant la rangée d'en-tête).

donc, je suis retourné à ma méthode VBScript classique et j'ai frappé ensemble une petite .script vbs qui peut être exécuté sur N'importe quel ordinateur Windows (il est exécuté automatiquement par le WScript.exe script host moteur sur Fenêtre.)

l'avantage de cette méthode est qu'elle utilise des flux de texte, de sorte que les données sous-jacentes ne sont pas chargées en mémoire (ou, au moins, pas toutes en même temps). Le résultat est qu'il est extrêmement rapide et il n'a pas vraiment besoin de beaucoup de mémoire pour exécuter. Le fichier de test que je viens de diviser en utilisant ce script sur mon i7 était d'environ 1 Go de taille de fichier, avait environ 12 millions de lignes de test et a fait 25 fichiers partiels (chacun avec environ 500k lignes de chaque) – le traitement a pris environ 2 minutes et il n'est pas allé plus loin Mémoire de 3 Mo utilisée à tout moment.

la mise en garde ici est qu'elle s'appuie sur le fichier texte ayant des" lignes "(ce qui signifie que chaque enregistrement est délimité par un CRLF) car L'objet de flux de texte utilise la fonction" ReadLine " pour traiter une seule ligne à la fois. Mais bon, si vous travaillez avec des fichiers TSV ou CSV, c'est parfait.

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
répondu Covenant 2015-10-27 18:23:56

ce" File Splitter "Windows command line program fonctionne bien: https://github.com/dubasdey/File-Splitter

c'est open source, simple, documenté, prouvé, et travaillé pour moi.

exemple:

fsplit -split 50 mb mylargefile.txt
5
répondu Fabian Kessler 2016-08-04 17:38:11

en voici un en Do qui ne manque pas de mémoire en se divisant en gros morceaux! J'avais besoin de diviser le fichier 95M en fichiers 10m x line.

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
répondu Mobigital 2017-07-06 23:41:30

j'ai créé un programme simple pour cela et votre question m'a aidé à compléter la solution... J'ai ajouté une autre fonctionnalité et quelques configurations. Dans le cas où vous voulez ajouter un caractère/ chaîne spécifique après chaque quelques lignes (configurable). S'il vous plaît aller à travers les notes. J'ai ajouté les fichiers de code : https://github.com/mohitsharma779/FileSplit

0
répondu User M 2017-09-19 15:51:13