Войти

Показать полную графическую версию : Разделение текстового файла на переменное количество частей и перемещение этих частей


krokradio
27-02-2016, 21:43
С Вашей помощью у меня получается создать папки с плейлистами
@echo off
setlocal enabledelayedexpansion
>nul chcp 1251

set "src=F:\Music\Test"
set "dest=F:\Music\MPL"
set "files=*.mp3"
set "playlistext=.alb"

2>nul (md "%dest%"
for /f "delims=" %%i in ('dir/ad/b "%src%"') do >"%dest%\%%i%playlistext%" dir/a-d/b/s "%src%\%%i\%files%")
For %%a in (F:\Music\MPL\*.alb) do md "F:\Music\MPL\%%~na"& move "%%~a" "F:\Music\MPL\%%~na"

for /f "tokens=*" %%i in ('dir /b /s F:\Music\MPL\*.alb') do (

for /f "tokens=*" %%j in ('type "%%i"') do call:set_random "%%j"
call:set_content "%%i"

)

goto:eof

:set_random
set "line_%random%=%~1"
goto:eof

:set_content

1>%1 (

for /f "tokens=2* delims==" %%i in ('set line_') do echo %%i

)

for /f "tokens=1 delims==" %%i in ('set line_') do set "%%i="

В папке "E:\Air\playlists" у меня лежит много подпапок. В каждой подпапке есть папка "elements"
E:\Air\playlists\Folder01\elements
E:\Air\playlists\Folder02\elements
E:\Air\playlists\Folder03\elements
E:\Air\playlists\*\elements

В папках "elements" лежат миниплейлисты. Их имена = именам плейлистов, которые созданы предыдущим скриптом, но с тегами 01, 02, 03...
Пример:
1. В папке "F:\Music\MPL\Chillout" есть файл "chillout.alb". В папке "E:\Air\playlists\Folder01\elements" есть файл "chillout01.alb", а в папке "E:\Air\playlists\Folder03\elements" есть файл "chillout02.alb". В остальных папках "E:\Air\playlists\*\elements" файлы "chillout**.alb" отсутствуют. Всего 2.
В папке "F:\Music\MPL\Trance" есть файл "trance.alb". В папке "E:\Air\playlists\Folder01\elements" есть файл "trance01.alb", в папке "E:\Air\playlists\Folder02\elements" есть файл "trance02.alb", а в папке "E:\Air\playlists\Folder04\elements" есть файл "trance03.alb". В остальных папках "E:\Air\playlists\*\elements" файлы "trance**.alb" отсутствуют. Всего 3.
2. После запуска скрипта он должен определить, что в подпапках "F:\Music\MPL" есть файл "chillout.alb", а во всех подпапках "E:\Air\playlists\*\elements" есть 2 файла с тегом "chillout" в названии. То же самое сравнение для "trance" и всех остальных.
3. Скипт разделяет файл "F:\Music\MPL\Chillout\chillout.alb" на "F:\Music\MPL\Chillout\chillout01.alb" и "F:\Music\MPL\Chillout\chillout02.alb" с одинаковым количеством строк. "F:\Music\MPL\Trance\trance.alb" разделяет на "F:\Music\MPL\Trance\trance01.alb", "F:\Music\MPL\Trance\trance02.alb" и "F:\Music\MPL\Trance\trance03.alb" с одинаковым количеством строк.
4. Замена существующих "E:\Air\playlists\*\elements\chillout**.alb" и "E:\Air\playlists\*\elements\trance**.alb" новыми "F:\Music\MPL\Chillout\chillout**.alb" и "F:\Music\MPL\Trance\trance**.alb"

Вот как-то так. Надеюсь я не путано объяснил, что я хочу получить в итоге?

krokradio
28-02-2016, 16:40
Упрощу задачу.
Есть структура директорий\файлов
F:\Music\MPL\Chillout(2)\chillout(2).alb
F:\Music\MPL\Trance(4)\Trance(4).alb
F:\Music\MPL\Rock(6)\Trance(6).alb
F:\Music\MPL\*(**)\*(**).alb

У нас получается 3 переменных:
Set "dir=F:\Music\MPL\*"
Set "name=F:\Music\MPL\*\*(**).alb"
Set "n=(**)
Я понимаю, что условия я изначально задаю не правильно и скорее всего оно должно иметь вид типа:
for /f "tokens=*" %%i in (ля-ля-ля) do (
лю-лю-лю
и т.д., но для меня программирование - темный лес. Могу экспериментировать только методом логической подстановки.

Скрипт должен смотреть на теги (**) файлов "*(**).alb" и разделять этот файл на (**) файлов с равным количеством строк, создавая например из файла "chillout(2).alb" два файла "chillout 01.alb" и "chillout 02.alb", после чего исходный файл "chillout(2).alb" удаляется.

krokradio
28-02-2016, 18:01
Вот что я сварганил на эту тему в смысле условий
@Echo On
SetLocal enabledelayedexpansion

:: Имена файлов:
:: F:\Music\MPL\Chillout_02\chillout_2.alb
:: F:\Music\MPL\Trance_04\Trance_4.alb
:: F:\Music\MPL\Rock_06\Rock_6.alb

For /F "tokens=* usebackq delims=_" %%i In ('dir /b /s F:\Music\MPL\*.alb') Do (

for /f "tokens=*" %%j in ('type "%%i"') do call:set_divided "%%j"

)

goto:eof

:set_divided

Set "Fullname=%%i"
Set "Filename=!Fullname:-6!"
Set "Tag=!Fullname:~Filename,-4!"


Но дальше я в ступоре. Те решения, которые я нашел в сети, относятся к разделению на заданное в условии количество строк. А вот как разделить на заданное количество равных частей - не нашел.

Foreigner
28-02-2016, 20:51
Из вашего объяснения мало чего понятно, я понял только, что надо разделить файл на равное кол-во строк. Пример, как можно разделить файл на равные части:

@echo off
setlocal

set cnt=100
set step=4

for /f "tokens=*" %%i in ('type test.txt') do call:0 "%%i"
for /l %%i in (101,%step%,%cnt%) do call:1 %%i
goto:eof

:0
set /a cnt+=1
set "line_%cnt%=%~1"
goto:eof

:1
set /a part+=1
set /a n=%1+step-1

1>test_%part%.txt (

for /l %%i in (%1,1,%n%) do if defined line_%%i (

for /f "tokens=2 delims==" %%j in ('set line_%%i') do echo %%j

))


В переменной step задается кол-во строк в каждом файле.
В последнем файле будет остаток.

ЗЫ. батники, это худший из вариантов для работы с текстом.
ЗЫЫ. Если вам надо просто составить плейлисты для эфира, то проще взять некоторое кол-во файлов из ВСЕЙ коллекции, в произвольном порядке и не мучиться с составлением каких-то промежуточных плейлистов. Например, нужно воспроизвести 10 произвольных файлов из 100 Гб музыки. Как я это решил для себя на PowerShell:

param ($count = 10, $root = 'D:\MUSIC')
$plist = (get-childitem $root *.mp3 -recurse | get-random -count $count).fullname
$plist

Результат вывода переменной $plist (ее можно сразу перенаправить в проигрыватель (зависит от проигрывателя) или сохранить в файл):

D:\MUSIC\NATIVE\Руян\2014. Лебедь Белая\06 - Дружина.mp3
D:\MUSIC\FOREIGN\The Sullen Route\2011. Apocalyclinic\06 - Tonight's Avenue.mp3
D:\MUSIC\FOREIGN\Rosetta\2015. Rosetta - Audio-Visual Original Score\04 - Tape A.mp3
D:\MUSIC\FOREIGN\Poets Of The Fall\2012. Temple Of Thought\03 - Cradled in Love.mp3
D:\MUSIC\FOREIGN\Heaven Shall Burn\2013. Veto\CD-1. Veto\11 - Beyond Redemption.mp3
D:\MUSIC\FOREIGN\Neurotech\2011. Antagonist\02 - Inject Me Now.mp3
D:\MUSIC\FOREIGN\Devin Townsend\The Devin Townsend Band\2006. Synchestra (Special Edition)\05 - Vampolka.mp3
D:\MUSIC\FOREIGN\Boards of Canada\2013. Tomorrow's Harvest\15 - New Seeds.mp3
D:\MUSIC\FOREIGN\Ill Niño\2012. Epidemia\10 - Invisible People.mp3
D:\MUSIC\FOREIGN\Riding Along For Thousands Of Miles\2011. Brick City Gost\07 - Final Notice.mp3

krokradio
28-02-2016, 22:56
Foreigner, примеров разделения по количеству строк много. Мне же нужно разделение на части.
Например есть 3 файла. В одном 2000 строк и его надо разделить на 4 равных части. то есть должно получиться 4 файла по 500 строк. В другом 1500 строк и его надо разделить на 2 части по 750 строк, в третьем 1500 строк и его надо разделить на 3 части по 500 строк.

Учитывая, что я в языках полный ноль, подскажите, будет ли ваш пример PowerShell работать в Win XP SP3? Возможно мне стоит описать полностью все задание и выложить на фрилансе? Но какой язык мне просить на реализацию задания? К сожалению я жестко привязан к Win XP SP3. Эфир полностью автоматизирован на QBasic.

Iska
29-02-2016, 00:12
будет ли ваш пример PowerShell работать в Win XP SP3? »
Будет. Надо только его установить: Windows Management Framework (Windows PowerShell 2.0, WinRM 2.0 и BITS 4.0) (https://support.microsoft.com/ru-ru/kb/968929).

Возможно мне стоит описать полностью все задание и выложить на фрилансе? »
Стоит. Не только на фрилансе, но и здесь.

Foreigner
29-02-2016, 00:17
Мне же нужно разделение на части. »
Ну и? Я ровно про это. Батник разделяет файл на части по количеству строк. Ведь равные части бывают разные, можно файл из 2000 строк и на 2000 частей разбить.

Попробовал файл из 1500 строк разбить на три файла по 500. Все отработало корректно. Файл создал в PowerShell (так проще):

& {for ($i = 1; $i -le 1500; $i++) { "$('{0:d4}. ' -f $i)$(get-random)" }} | sc test.txt

Он имеет вид:

0001. 1684051906
0002. 150225868
0003. 538389330
0004. 541472203
...
1500. 233788911

Батник слегка изменил под большее число строк:

@echo off
setlocal

set cnt=10000
set step=500

for /f "tokens=*" %%i in ('type test.txt') do call:0 "%%i"
for /l %%i in (10001,%step%,%cnt%) do call:1 %%i
goto:eof

:0
....

В результате появилось три файла по 500 строк (0001...0500; 0501...1000; 1001...1500)

Проблема батника при работе с текстом -- есть большая вероятность, что при попадании в раздачу спец.символов (=,&,|,%,>,<) результат может оказаться не тем, который вы ожидаете увидеть. Все это так или иначе решается, но если честно нет особого желания этого делать.

Ну а PowerShell на Win ХР надо ставить дополнительно (будет вторая версия) + Net.Framework. Код, с небольшими изменениями, будет работать:

param ($count = 10, $root = 'D:\MUSIC')
$plist = get-childitem $root *.mp3 -recurse | get-random -count $count | % { $_.fullname }
$plist

Iska
29-02-2016, 01:12
Ну и? Я ровно про это. »
Не совсем. Нужно дополнительное действие, ибо, насколько я понимаю, он хочет делить не по X строк, а на Y частей, то есть — посчитать количество строк в файле и разделить на эти самые Y частей.

Проблема батника при работе с текстом -- есть большая вероятность, что при попадании в раздачу спец.символов (=,&,|,%,>,<) результат может оказаться не тем, который вы ожидаете увидеть. Все это так или иначе решается, но если честно нет особого желания этого делать. »
Всецело поддерживаю :)!

krokradio
29-02-2016, 01:16
alb=txt
Весь скрипт должен отталкиваться от ini-файла в абзаце 5.

1. Есть коллекция музыки, распределенная в папках по стилям.
F:\Music\Chillout_2
F:\Music\Trance_4
F:\Music\Rock_5
F:\Music\*_*

2. Есть папки с плейлистами, из которой мой плеер берет информацию для эфира
E:\Air\playlists\one
E:\Air\playlists\two
E:\Air\playlists\three
E:\Air\playlists\four
E:\Air\playlists\*

3. В каждой папке "E:\Air\playlists\*" есть подпапка "elements" и файл MAIN.alb

В принципе уже есть скрипт "Windows Batch file", который создает из коллекции готовые плейлисты, но учитывая весь объем задания, скорее всего его придется переписывать под другой язык
@echo off
setlocal enabledelayedexpansion
>nul chcp 1251

set "src=F:\Music"
set "dest=F:\MPL"
set "files=*.mp3"
set "playlistext=.alb"

2>nul (md "%dest%"
for /f "delims=" %%i in ('dir/ad/b "%src%"') do >"%dest%\%%i%playlistext%" dir/a-d/b/s "%src%\%%i\%files%")
For %%a in (F:\MPL\*.alb) do md "F:\MPL\%%~na"& move "%%~a" "F:\MPL\%%~na"

for /f "tokens=*" %%i in ('dir /b /s F:\MPL\*.alb') do (

for /f "tokens=*" %%j in ('type "%%i"') do call:set_random "%%j"
call:set_content "%%i"

)

goto:eof

:set_random
set "line_%random%=%~1"
goto:eof

:set_content

1>%1 (

for /f "tokens=2* delims==" %%i in ('set line_') do echo %%i

)

for /f "tokens=1 delims==" %%i in ('set line_') do set "%%i="

Этот скрипт опираясь на структуру папок в "F:\Music" создает в папке "F:\MPL" такую же структуру директорий и в каждую подпапку кладет плейлист с таким же именем, как и у подпапки.
На выходе получается

F:\MPL\Chillout_2\chillout_2.alb
F:\MPL\Trance_4\Trance_4.alb
F:\MPL\Rock_5\Rock_5.alb
F:\MPL\*_*\*_*.alb
ВАЖНО!!! Как видно из кода, эти плейлисты создаются уже перемешанными, то есть с функцией "random".

4. У каждого созданного плейлиста в имени есть цифровой тег "_*". Этот тег задает количество миниплейлистов, на которое должен быть разбит плейлист. То есть, если у нас есть "F:\MPL\Chillout_2\chillout_2.alb" на "х" строк, то из него должно получится "F:\MPL\Chillout_2\chillout 01.alb" на "Х/2" строк и "F:\MPL\Chillout_2\chillout 02.alb" на "х/2" строк а сам "F:\MPL\Chillout_2\chillout_2.alb" должен быть удален.
Если в теге файла кроме основного есть еще значение "с" (на пример "F:\MPL\Jazz_c_10\Jazz_c_10.alb"), то файл не разбивается на строки, а из него просто делается 10 копий с именами
F:\MPL\Jazz_c_10\Jazz 01.alb
F:\MPL\Jazz_c_10\Jazz 02.alb
F:\MPL\Jazz_c_10\Jazz 03.alb
.......
F:\MPL\Jazz_c_10\Jazz 10.alb
а сам "F:\MPL\Jazz_c_10\Jazz_c_10.alb" должен быть удален.

5. Перемещение. Я создам "F:\MPL\plst.ini" в котором задам соответствие такого типа
Music = F:\Music
Playlists = F:\MPL
E:\Air\playlists\one\elements = Chillout, New Age
E:\Air\playlists\two\elements = Chillout, Trance, New Age
E:\Air\playlists\three\elements = Trance, Jazz
E:\Air\playlists\four\elements = Jazz, Rock
и т.д.

Вот тут как бы правильно объяснить....
Для начала все папки "E:\Air\playlists\*\elements" должны очищаться.
В примерах выше я разбивал "F:\MPL\Chillout_2\chillout_2.alb" на "F:\MPL\Chillout_2\chillout 01.alb" и "F:\MPL\Chillout_2\chillout 02.alb".
В "F:\MPL\plst.ini" у нас указано, что "F:\MPL\Chillout_2\chillout 01.alb" и "F:\MPL\Chillout_2\chillout 02.alb" должны попадать в "E:\Air\playlists\one\elements" и "E:\Air\playlists\two\elements".
То есть "chillout 01.alb" перемещается в "E:\Air\playlists\one\elements", "chillout 02.alb" в "E:\Air\playlists\two\elements". И так для остальных...

6. После такого распределения у нас в папках "E:\Air\playlists\*\elements" оказывается много миниплейлистов. На пример в папке "E:\Air\playlists\two\elements" появляется три миниплейлиста ("Chillout 02.alb", "Trance 01.alb" и "New Age 02.alb").
Выше я писал, что в каждой папке "E:\Air\playlists\*" есть файл "MAIN.alb". Нам нужно файлы "Chillout 02.alb", "Trance 01.alb" и "New Age 02.alb" соединить в один, перемешать/рандомизировать его и сохранить как "E:\Air\playlists\*\MAIN.alb" заменив им старый.

Вот как-то так. Предложения в личку.

Проблема батника при работе с текстом -- есть большая вероятность, что при попадании в раздачу спец.символов (=,&,|,%,>,<) результат может оказаться не тем, который вы ожидаете увидеть. Все это так или иначе решается, но если честно нет особого желания этого делать. »

Такого получится не может, так как я всю базу музыки предварительно прогоняю через TagScaner избавляясь не только от спецсимволов, но даже на всякий случай от букв "й" и "ё".

насколько я понимаю, он хочет делить не по X строк, а на Y частей, то есть — посчитать количество строк в файле и разделить на эти самые Y частей. »
Абсолютно верно

Foreigner
29-02-2016, 02:17
Абсолютно верно »
Это почти одно и тоже, просто делим кол-во строк на кол-во частей:

@echo off
setlocal

set cnt=10000
set p=4

for /f "tokens=*" %%i in ('type test.txt') do call:0 "%%i"
set /a step=(cnt-10000)/p
.....

Где переменная %p% кол-во частей

krokradio
29-02-2016, 13:16
Всем спасибо. Принято в работу фрилансером.




© OSzone.net 2001-2012