batch-file - extensiones - tipos de formatos de texto
Divida el archivo de texto en un archivo de texto múltiple más pequeño usando la línea de comando (9)
Tengo varios archivos de texto con aproximadamente 100,000 líneas y quiero dividirlos en archivos de texto más pequeños de 5000 líneas cada uno.
Solía:
split -l 5000 filename.txt
Eso crea archivos:
xaa
xab
aac
xad
xbe
aaf
archivos sin extensiones Solo quiero llamarlos algo así como:
file01.txt
file02.txt
file03.txt
file04.txt
o si eso no es posible, solo quiero que tengan la extensión ".txt".
¡Aquí hay uno en c # que no se queda sin memoria cuando se divide en trozos grandes! Necesitaba dividir el archivo de 95M en 10M x archivos de línea.
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();
Aquí hay un ejemplo en C # (porque eso es lo que estaba buscando). Necesitaba dividir un archivo csv de 23 GB con alrededor de 175 millones de líneas para poder ver los archivos. Lo dividí en archivos de un millón de filas cada uno. Este código lo hizo en aproximadamente 5 minutos en mi máquina:
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);
Este programa de línea de comandos de Windows "Splitter de archivos" funciona muy bien: https://github.com/dubasdey/File-Splitter
Es de código abierto, simple, documentado, probado y funcionó para mí.
Ejemplo:
fsplit -split 50 mb mylargefile.txt
He creado un programa simple para esto y su pregunta me ayudó a completar la solución ... Agregué una característica más y algunas configuraciones. En caso de que quiera agregar un carácter / cadena específico después de cada pocas líneas (configurable). Por favor revisa las notas. He agregado los archivos de código: https://github.com/mohitsharma779/FileSplit
La sintaxis se ve así:
$ split [OPTION] [INPUT [PREFIX]]
donde el prefijo es PREFIXaa, PREFIXab, ...
Simplemente use uno adecuado y listo o simplemente use mv para cambiar el nombre. Creo que $ mv * *.txt
debería funcionar, pero pruébelo primero a menor escala.
:)
Mi requerimiento era un poco diferente. A menudo trabajo con archivos delimitados por comas y delimitados por tabulaciones ASCII donde una sola línea es un único registro de datos. Y son realmente grandes, así que necesito dividirlos en partes manejables (conservando al mismo tiempo la fila del encabezado).
Por lo tanto, volví a mi método clásico VBScript y mezclé un pequeño script .vbs que se puede ejecutar en cualquier computadora con Windows (se ejecuta automáticamente con el motor de script WScript.exe en la ventana).
El beneficio de este método es que utiliza Text Streams, por lo que los datos subyacentes no se cargan en la memoria (o, al menos, no todos a la vez). El resultado es que es excepcionalmente rápido y no necesita mucha memoria para funcionar. El archivo de prueba que acabo de dividir con esta secuencia de comandos en mi i7 era de aproximadamente 1 GB en tamaño de archivo, tenía alrededor de 12 millones de líneas de prueba y 25 archivos de partes (cada uno con aproximadamente 500k líneas cada uno) - el procesamiento duró 2 minutos y no lo hizo No utilice más de 3 MB de memoria utilizada en cualquier punto.
La advertencia aquí es que se basa en que el archivo de texto tiene "líneas" (lo que significa que cada registro está delimitado con un CRLF) ya que el objeto Text Stream usa la función "ReadLine" para procesar una sola línea a la vez. Pero, si trabajas con archivos TSV o CSV, es perfecto.
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())
Sé que la pregunta fue hecha hace mucho tiempo, pero estoy sorprendido de que nadie haya dado la respuesta de Unix más directa:
split -l 5000 -d --additional-suffix=.txt $FileName file
-
-l 5000
: divide el archivo en archivos de 5.000 líneas cada uno. -
-d
: sufijo numérico. Esto hará que el sufijo vaya de 00 a 99 de forma predeterminada en lugar de aa a zz. -
--additional-suffix
: le permite especificar el sufijo, aquí la extensión -
$FileName
: nombre del archivo a dividir. -
file
: prefijo para agregar a los archivos resultantes.
Como siempre, revisa el man split
para más detalles.
Para Mac, la versión predeterminada de la split
aparentemente está embotada. Puede instalar la versión de GNU con el siguiente comando. ( vea esta pregunta para más utilidades de GNU )
brew install coreutils
y luego puede ejecutar el comando anterior reemplazando split
con gsplit
. Echa un vistazo a man gsplit
para más detalles.
Tal vez puedas hacer algo como esto con awk
awk ''{outfile=sprintf("file%02d.txt",NR/5000+1);print > outfile}'' yourfile
Básicamente, calcula el nombre del archivo de salida tomando el número de registro (NR) y dividiéndolo por 5000, agregando 1, tomando el número entero y cero relleno en 2 lugares.
De manera predeterminada, awk
imprime todo el registro de entrada cuando no especifica nada más. Por lo tanto, print > outfile
escribe todo el registro de entrada en el archivo de salida.
A medida que se ejecuta en Windows, no puede usar comillas simples porque no le gusta. Creo que debes poner el script en un archivo y luego decirle a awk
que use el archivo, algo como esto:
awk -f script.awk yourfile
y script.awk
contendrá el script de esta manera:
{outfile=sprintf("file%02d.txt",NR/5000+1);print > outfile}
O bien, puede funcionar si haces esto:
awk "{outfile=sprintf(/"file%02d.txt/",NR/5000+1);print > outfile}" yourfile
@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
Aquí hay un lote de Windows nativo que debería realizar la tarea.
Ahora no diré que será rápido (menos de 2 minutos por cada archivo de salida de 5Kline) o que será inmune a los caracteres sensibles a los lotes. Realmente depende de las características de tus datos objetivo.
q25249516.txt
un archivo llamado q25249516.txt
contiene 100Klines de datos para mi prueba.
Versión revisada más rápida
movimiento rápido del ojo
@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
Tenga en cuenta que utilicé llimit
de 50000 para probar. llimit
los primeros números de archivo si llimit
* 100 es mayor que el número de líneas en el archivo ( fcount
configurando fcount
en 1999
y use ~3
en lugar de ~2
en la línea de cambio de nombre de archivo).