PowerShell, Get-LiveJournal: сохранение полученных постов

Mar 17, 2023 15:03

Окружение: операционная система «Windows 10», программа-оболочка «PowerShell» версии 7, скрипт «Get-LiveJournal».

На первый взгляд кажется, что сохранение данных, полученных из тел HTTP(S)-ответов программы-сервера ЖЖ («Живого Журнала») - это очень простая задача. Но это не так. Порядок сохранения данных зависит от того, как вы собираетесь использовать эти данные, а также от того, как будет работать ваш веб-клиент. В принципе, можно просто сохранить полученные данные в текстовый файл (или несколько файлов). Я уже разбирал, как это сделать в отдельном посте про простейшее кэширование.

Тут сразу возникает вопрос: так в один текстовый файл писать все тела HTTP(S)-ответов с данными постов или каждый HTTP(S)-ответ писать в отдельный файл? В одном из предыдущих постов я уже пояснял, что удобнее писать тело каждого HTTP(S)-ответа в отдельный текстовый файл. Так их удобнее будет разбирать позже. Если все тела HTTP(S)-ответов записать в один файл, то может возникнуть путаница при разборе полученных данных из-за того, что программа-сервер ЖЖ нумерует возвращаемые посты, начиная каждый раз с единицы для каждой порции постов. Об этом сказано в документации к удалённой функции «getevents» (интерфейс «flat»):

events_count
The number of events being returned. The records returned are number from 1 to events_count.

Итак, я решил, что текстовых файлов с данными постов будет столько же, сколько скрипт получит порций постов (для каждой порции - отдельный текстовый файл).

Следующий вопрос: как будут называться эти файлы? Очевидно, что у них должны быть разные названия, чтобы они не затерли друг друга. Простая нумерация файлов от единицы и далее показалась мне недостаточно информативной. Я решил, что название файла должно еще давать некую информацию пользователю, чтобы всё было понятно при одном взгляде на список файлов. В итоге я решил, что название файла должно содержать значение входного параметра «lastsync» (дата и время, начиная с которых удалённая функция «getevents» возвращает порцию в 100 постов) и количество полученных в данной порции постов. Вот как это выглядит для журнала «vbgtut» (напомню, в этом журнале всего 147 постов на данный момент):

1970-01-01 00.00.00-100.txt
2012-06-25 20.09.40-47.txt

В блоке кода выше в названиях файлов сначала вписано значение входного параметра «lastsync» (дата и время), а потом, через дефис, количество постов, сохраненное в данном файле. В первом файле - 100 постов, во втором - 47, всего - 147 постов.

Напомню, первую порцию постов я получаю без указания входного параметра «lastsync», поэтому в этом случае в название файла пришлось вписать дату и время по умолчанию, то есть дату и время начала «эпохи Unix» (1 января 1970 года 00:00:00).

При формировании даты слева направо указаны год, месяц и день.

При указании времени в качестве разделителя часов, минут и секунд обычно используют символ двоеточия :, но символ двоеточия запрещено использовать в названиях файлов в операционных системах «Windows» (напомню, я работаю в операционной системе «Windows 10»). Поэтому я решил в качестве разделителя использовать символ точки. При указании времени слева направо указаны сначала часы, потом минуты, и в заключение - секунды. При указании часов используется 24-часовой формат.

Скачивание постов для разных журналов

Далее я стал думать, а как же действовать, если я буду скачивать посты нескольких журналов? Файлы для разных журналов могут перемешаться между собой, а некоторые могут затереть друг друга, если эти файлы будут храниться в одной и той же папке. Я решил, что текстовые файлы с постами разных журналов должны сохраняться в разных папках, которые будут создаваться внутри папки, из которой будет запущен скрипт «Get-LiveJournal». Что-то вроде следующего:

.\Get-LiveJournal.ps1
.\vbgtut\
1970-01-01 00.00.00-100.txt
2012-06-25 20.09.40-47.txt
.\ilyachalov\
1970-01-01 00.00.00-100.txt
...

Выражение .\ перед названием скрипта и названиями папок означает, что вместо символа точки в этом выражении программа-оболочка подставит текущее местоположение. То есть с помощью выражения .\ мы указываем так называемый относительный путь.

Здесь следует иметь в виду, что командлет «Out-File», который я использую для создания файлов, сработает успешно, только если в указанном ему пути все папки существуют. То есть я не могу этим командлетом при сохранении текстового файла с первой порцией постов одновременно создать папку для текущего журнала и записать в нее текстовый файл. Для использования командлета «Out-File» папка журнала уже должна существовать. Чтобы это реализовать, я в скрипте «Get-LiveJournal» перед сохранением текстового файла имею что-то вроде следующего:

if (!(Test-Path -Path ".\$user\")) {
New-Item -ItemType "directory" -Path ".\$user\" | Out-Null
}

В блоке кода выше я сначала проверяю существование нужной папки с помощью командлета «Test-Path». Если нужная папка отсутствует в указанном местоположении, я создаю ее с помощью командлета «New-Item». Отмечу, что этот командлет может при необходимости создать несколько вложенных друг в друга папок по указанному ему пути. Эта фишечка еще понадобится нам позже.

Повторные запуски скрипта для того же журнала

Если бы я писал полноценный веб-клиент для работы с ЖЖ, то при повторных запусках веб-клиента для того же журнала следовало бы дозагружать новые посты и обновления старых постов с момента предыдущего запуска веб-клиента для этого журнала. То есть следовало бы выполнять синхронизацию локальной копии данных с оригиналом на сервере ЖЖ. Я же написал гораздо более простой скрипт, который лишь загружает все посты указанного журнала, независимо от того, что было скачано для этого журнала в прошлый раз.

Можно было бы просто затирать файлы, загруженные для данного журнала в прошлый раз. Но я решил, что мой скрипт будет загружать посты для указанного журнала каждый раз с нуля, не затирая файлы, полученные в предыдущие разы. Для этого в папке журнала я решил разбивать файлы по дополнительным папкам. При этом название дополнительной папки будет содержать дату и время текущего запуска скрипта. Если в названиях файлов дата и время - это дата и время сервера ЖЖ, то в названии папки я решил использовать дату и время своего компьютера. Должно получиться что-то вроде следующего:

.\vbgtut\
2023-03-11 07.32.01\
1970-01-01 00.00.00-100.txt
2012-06-25 20.09.40-47.txt
2023-03-17 13.53.33\
...

Чтобы обеспечить такую структуру, я изменил код создания папки на следующий (изменения помечены красным цветом):

if (!(Test-Path -Path ".\$user\$folder\")) {
New-Item -ItemType "directory" -Path ".\$user\$folder\" | Out-Null
}

Вот тут и пригодилась упомянутая выше фишечка командлета «New-Item», заключающаяся в том, что он может создавать по указанному пути вложенные друг в друга папки. То есть в данном случае он сначала создаст папку «vbgtut» (если она не существует), а затем создаст папку с датой запуска скрипта (если она не существует).

Код создания файлов

Вот какой код получился для создания текстового файла с постами:

$Response.Content | Out-File -FilePath ".\$user\$folder\$datetime-$($params["events_count"]).txt" `
-NoNewline -NoClobber
if ($?) { ".\$user\$folder\$datetime-$($params["events_count"]).txt" }

Я очень долго думал, оставлять ли параметр -NoClobber (запрещает сохранять файл, если файл с таким именем уже существует; если возникнет такая ситуация, будет выдано сообщение об ошибке в окно программы-оболочки и файл создан не будет, но выполнение скрипта не прервется) командлета «Out-File», и в конце концов решил на всякий случай его оставить. Но я проектировал изложенную выше систему названий файлов и папок для того, чтобы не возникло ситуации, в которой скрипт будет пытаться затереть уже существующий файл. Так что, по идее, такой ситуации возникнуть не должно.

Командлет «Out-File» только создает указанный файл (или не создает, если возникла какая-либо проблема) и ничего не возвращает в скрипт. Однако, мне нужно как-то понять, успешно ли командлет «Out-File» создал файл или нет. В случае ошибки сообщение об ошибке будет выдано в окно программы-оболочки автоматически. А вот в случае успеха в окно программы-оболочки не будет выдано ничего, а я хочу показать пользователю скрипта название созданного файла.

Чтобы узнать об успехе предыдущей команды, в программе-оболочке «PowerShell» есть встроенная переменная $?. Эта переменная будет содержать значение $true, если предыдущая в скрипте команда была успешно выполнена, в противном случае она будет содержать значение $false. Как видно в блоке кода выше, ориентируясь на значение этой встроенной переменной, я вывожу сообщение о создании файла в окно программы-оболочки.

Инструмент, Образование, Сайтостроение, Программирование, Английский язык, ЖЖ

Previous post Next post
Up