Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Разбить тхт файл не только по строкам, но и по папкам (http://forum.oszone.net/showthread.php?t=335690)

Abricosio 11-07-2018 15:15 2821522

Разбить тхт файл не только по строкам, но и по папкам
 
В замечательной теме раскрывается вопрос, как разбить большой тхт файл на много мелких по кол-ву строк
Моя задача чуть шире. Есть файл на 10 млн строк. Мне нужно получить 100 папок, в каждой по 100 файлов тхт, в каждом файле по 1000 строк из стартового файла.
Названия папок 1,2,3,4,5,...,100
Названия файлов 1.txt, 2.txt, 3.txt, ..., 100.txt

Кто-нибудь может помочь с этой непосильной для меня задачей?

YuS_2 11-07-2018 15:29 2821525

Цитата:

Цитата Abricosio
Кто-нибудь может помочь с этой непосильной для меня задачей? »

CMD тут вряд ли поможет... 10 млн. строк... подавится считать... :)
Лучше вооружитесь powershell-ом.

Abricosio 11-07-2018 15:32 2821526

А как powershellом это сделать? :)

Iska 11-07-2018 17:04 2821536

Abricosio, размер файла:
Цитата:

Цитата Abricosio
Есть файл на 10 млн строк. »

каков? В мегабайтах?

Busla 11-07-2018 17:59 2821548

Цитата:

Цитата Abricosio
как powershellом это сделать? »

просто по файлам раскидать вот так:
Код:

$counter = 0; $linesPerFile=10000; Get-Content .\big.log | ForEach-Object { $counter++; Add-Content -Path "$(($counter/$linesPerFile).ToString('000000')).log" -Value $_ }
к сожалению, в реализации Add-Content Микрософт накосипорила - директории он автоматически не создаёт, поэтому коротко не написать :(
После Get-Content указываете путь к файлу, в текущей директории создаются файлы по 10 тыс строк (количество задаётся переменной $linesPerFile)

Цитата:

Цитата Iska
размер файла:
каков? В мегабайтах? »

это неважно, не требуется никакого хитрого анализа, чтобы его его целиком в память пихать

YuS_2 11-07-2018 18:00 2821549

Цитата:

Цитата Abricosio
А как powershellом это сделать? »

Как-то так:
Код:

$fl = 'test.txt'
$root = 'root'
if (!(test-path $root)){md $root|out-null}
gc $fl -read 1000|%{$i,$n=1,1}{
        $tmp = "$root\$n"
        if(!(test-path $tmp)){md $tmp|out-null}
        set-content -path "$tmp\$i.txt" -val $_
        switch ($i) {
          100 {$n++;$i=0}
        }
        $i++
}

Цитата:

Цитата Busla
чтобы его его целиком в память пихать »

если его целиком пихать в память, powershell загнется не хуже (или не лучше?) cmd :)

Busla 11-07-2018 18:36 2821554

Цитата:

Цитата YuS_2
если его целиком пихать в память, powershell загнется не хуже (или не лучше?) cmd »

и сам делаешь то же самое: если пользователь решит делить файл не на 100 тыс. файлов, а на два? - всё переписывать?

YuS_2 11-07-2018 18:43 2821556

Цитата:

Цитата Busla
и сам делаешь то же самое »

где? присмотрись повнимательнее...

Разве что, можно чуток оптимизировать, чтобы не дергать $tmp при каждой итерации:
Код:

$fl = 'test.txt'
$root = 'root'
if (!(test-path $root)){md $root|out-null}
gc $fl -read 1000|%{$i,$n=1,1;$tmp = "$root\$n"}{
        if(!(test-path $tmp)){md $tmp|out-null}
        set-content -path "$tmp\$i.txt" -val $_
        switch ($i) {
          100 {$n++;$i=0;$tmp = "$root\$n"}
        }
        $i++
}


Iska 11-07-2018 19:41 2821561

Цитата:

Цитата Busla
это неважно, не требуется никакого хитрого анализа, чтобы его его целиком в память пихать »

Э… Ну, запихните в память текстовый файл в десять-двадцать гигабайт.

Busla 11-07-2018 20:17 2821563

Цитата:

Цитата YuS_2
где? »

результирующий файл формируется в памяти и за раз пишется инструкцией set-content

Цитата:

Цитата Iska
Ну, запихните в память текстовый файл в десять-двадцать гигабайт. »

зачем?

YuS_2 11-07-2018 20:31 2821564

Цитата:

Цитата Busla
результирующий файл формируется в памяти и за раз пишется инструкцией set-content »

И что? Я говорю о:
Код:

gc text.txt
и
Код:

gc text.txt -readcount 1000
В первом случае, по конвейеру будет передаваться первая строка только после помещения всего файла в память (что может привести к достаточно длительному ожиданию, если не зависанию, при достаточно большом файле). Во втором случае, первая строка (вернее блок строк) передается после помещения в память некоторого количества строк -readcount <int64>, что значительно ускоряет процесс... в общем, попробуйте, тогда станет понятно в чем разница.

Iska 11-07-2018 20:44 2821566

Цитата:

Цитата Busla
зачем? »

Затем, что не поместится.

Abricosio 11-07-2018 22:00 2821574

Все отлично в примере на павершел, один только нюанс - пустая строчка в самом конце, но я ее регуляркой почикаю) Спасибо!

Busla 11-07-2018 22:10 2821575

YuS_2, неверно
по умолчанию readcount равно единице, чтобы прочитать весь файл за раз нужно принудительно выставить нуль

Вы смешали в одно "буфер чтения" и размер выходного файла. Всё это "значительно ускоряет процесс" пока файлы крохотные. А как только понадобится напилить файл на куски по несколько ГБ (например, чтобы на DVD записать) - так сразу скрипту и поплохеет.

Iska 11-07-2018 22:23 2821577

Busla, YuS_2, в документации сказано, что:
Цитата:

-ReadCount <Int64>
Specifies how many lines of content are sent through the pipeline at a time. The default value is 1. A value of 0 (zero) sends all of the content at one time.

This parameter does not change the content displayed, but it does affect the time it takes to display the content. As the value of ReadCount increases, the time it takes to return the first line increases, but the total time for the operation decreases. This can make a perceptible difference in very large items.
но ничего не сказано про собственно само чтение. Как с этим обстоит дело?

Abricosio 11-07-2018 22:38 2821580

А нет, не получается, регуляркой эту строку не видно, удалить массово через notepad++ не получается. Возможно ли переделать скрипт, чтобы он не делал 1001-ю пустую строку?
Заранее большое спасибо!

Iska 11-07-2018 22:45 2821581

Abricosio, там нет «пустой строки»:



где Вы её нашли?!

Abricosio 11-07-2018 23:04 2821582

Странно, у меня во всех файлах последняя строка пустая, 1001я. Проверял в notepad++ и обычном тхт редакторе

Iska 12-07-2018 00:32 2821588

Abricosio, это:



не «пустая строка».

Пустая строка — вот:



Если Вам категорически нужно, чтобы последняя строка не завершалась символами конца строки:



— это другое дело.

YuS_2 12-07-2018 05:40 2821597

Цитата:

Цитата Busla
чтобы прочитать весь файл за раз »

Код:

gc text.txt -raw
Цитата:

Цитата Busla
Вы смешали в одно "буфер чтения" и размер выходного файла. »

Я? Где? :)
Лично я говорил о том, что вредно помещать весь файл (при условии, что он достаточно большой) в память, чтобы производить с ним дальнейшие манипуляции. О размерах выходного файла заговорил ты, я ничего об этом не писал.

Цитата:

Цитата Busla
А как только понадобится напилить файл на куски по несколько ГБ (например, чтобы на DVD записать) - так сразу скрипту и поплохеет. »

Чтобы поменьше теоретизировать, предлагаю провести простой эксперимент:
1. Создай текстовый файл (UTF8, хотя это неважно), в 10000000 строк, с одним символом в каждой строке. Размер у него получится не сильно большим (чуть больше 28Мб), но достаточным для эксперимента. Возможно, конфигурация компьютера будет влиять на результат, но это можно "поправить" увеличением количества строк. :)
2.
a)
Код:

gc text.txt -read 5000000|set-content text-out.txt
b)
Код:

gc text.txt|set-content text-out.txt
3. Приведи здесь результат эксперимента.

Мои результаты:
a) TotalSeconds : 6,9191207
b) Неадекватное потребление физ.памяти до 3,5Гб и более процессом powershell, нагрузка процессора в 50% и более, плюс подвисания интерфейса windows. Терпения, чтобы дождаться окончания процесса (если это реально), у меня не хватило. В общем, плохеет не только скрипту и размер у файла не очень-то огромный... :)

Abricosio 12-07-2018 09:10 2821614

Iska, а есть какое-нибудь регулярное выражение для такого случая?

Iska 13-07-2018 16:51 2821641

Abricosio, чем Вас текущее состояние не устраивает?

x0r 13-07-2018 17:52 2821652

А не лучше будет в таких запущенных случаях(миллионы строк) отдать разбивку норм. проге на Цэ\Цэ++ - тот же Winrar , а потом собирать уже скриптом.
Ну т.е. отдать Winrar-у этот "миллионнострочный_файл" и нехай он его разбивает на фрагменты по 300kb(или скокатам получаеццо размер файла из 1000 строк). А потом эти фрагменты разложить по-папкам. :search:

YuS_2 13-07-2018 20:39 2821680

Цитата:

Цитата x0r
не лучше будет в таких запущенных случаях(миллионы строк) отдать разбивку норм. проге на Цэ\Цэ++ - тот же Winrar , а потом собирать уже скриптом. »

:no:
не лучше... вернее, чем лучше?
хорошо, вот полный тест:

Код:

$watch = [diagnostics.stopwatch]::startnew()
$watch.start()

$cnt = 10000000
$str = new-object text.stringbuilder
for($k=1;$k -le $cnt; $k++){
        $null = $str.append("строка для теста`r`n")
}
($str.tostring()).trim()|sc test.txt -enc utf8

$fl = 'test.txt'
$root = 'root'
if (!(test-path $root)){md $root|out-null}
gc $fl -read 1000 -enc utf8|%{$i,$n=1,1;$tmp = "$root\$n"}{
        if(!(test-path $tmp)){md $tmp|out-null}
        set-content -path "$tmp\$i.txt" -val $_ -enc utf8
        switch ($i) {
          100 {$n++;$i=0;$tmp = "$root\$n"}
        }
        $i++
}

$watch.stop()
$watch.elapsed >timelog.txt

и создает, и разбивает, и считает время выполнения.
Код:

Days              : 0
Hours            : 0
Minutes          : 1
Seconds          : 25
Milliseconds      : 164
Ticks            : 851640521
TotalDays        : 0,000985695047453704
TotalHours        : 0,0236566811388889
TotalMinutes      : 1,41940086833333
TotalSeconds      : 85,1640521
TotalMilliseconds : 85164,0521

- это достаточно вменяемые цифры


Время: 19:04.

Время: 19:04.
© OSzone.net 2001-