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.
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.
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);
@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.)
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
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.
:)
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())
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
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();
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