Мое требование было немного другим. Я часто работаю с файлами ASCII с разделителями-запятыми и табуляцией, где одна строка - это одна запись данных. И они действительно большие, поэтому мне нужно разделить их на управляемые части (сохранив при этом строку заголовка).
Итак, я вернулся к своему классическому методу VBScript и собрал небольшой скрипт .vbs, который можно запустить на любом компьютере Windows (он автоматически запускается механизмом хоста скрипта WScript.exe в Window).
Преимущество этого метода в том, что он использует текстовые потоки, поэтому базовые данные не загружаются в память (или, по крайней мере, не все сразу). Результатом является то, что он исключительно быстрый и не требует много памяти для запуска. Тестовый файл, который я только что разделил с помощью этого сценария на моем i7, имел размер около 1 ГБ, имел около 12 миллионов строк текста и был разбит на 25 файлов по частям (каждый по 500 тысяч строк в каждом) - обработка заняла около 2 минут и он не превышал 3 МБ памяти, используемой в любой момент.
Предостережение заключается в том, что он опирается на текстовый файл, имеющий «строки» (то есть каждая запись ограничена CRLF), поскольку объект Text Stream использует функцию «ReadLine» для обработки одной строки за раз. Но, эй, если вы работаете с файлами TSV или CSV, это прекрасно.
Option Explicit
Private Const INPUT_TEXT_FILE = "c:\bigtextfile.txt"
Private Const REPEAT_HEADER_ROW = True
Private Const LINES_PER_PART = 500000
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())