Качаємо 16GB торент через планшет з 4GB вільного місця
Завдання:
Є ПК без інтернету, але є можливість перекинути файл по USB. Є планшет з інтернетом, з якого цей файл можна перекинути. На планшет можна завантажити необхідний торрент, але мало вільного місця. Файл у торренті один і великий.
Шлях до вирішення:
Я запустив торент на завантаження. Коли вільне місце майже добігло кінця я поставив завантаження на паузу. Підключив планшет до ПК та перемістив файл із планшета на ПК. Віджав паузу і на мій подив файл був знову створений і торрент продовжив хитатися далі як ні в чому не бувало.
Завдяки тому, що торрент клієнт встановлює sparse прапор файлу, в який записує отримані дані, система не намагається зарезервувати відразу 16GB і не виникне помилки при спробі запису в файл далі 4GB.
Повторивши процедуру чотири рази, я отримав на ПК чотири файли в якому різні частини одного і того ж торрента. Тепер залишилося зібрати їх докупи. Процедура насправді проста. Потрібно замінити нуль байти на інше значення, якщо воно є в цій позиції в одному з чотирьох файлів.
Мені здавалося, що така проста програмка повинна бути в інтернеті. Невже ніхто не стикався з таким завданням? Але я зрозумів, що навіть не знаю за якими ключовими словами її шукати. Тому я швидко накидав Lua скрипт під це завдання, а тепер вже й оптимізував його. Їм і хочу поділитись.
Завантажуємо торрент частинами
запускаємо завантаження торрента на першому пристрої
чекаємо поки заповниться ПЗУ
ставимо завантаження на паузу
переносимо файл на другий пристрій та додаємо до імені файлу цифру
повертаємося до першого пункту до тих пір, поки файл не скачається повністю
Зливаємо частини в один файл
Після того, як отримана остання частина, необхідно зібрати їх в один цілий файл.
Завдання просте:
Читаємо всі частини одночасно
Якщо в якійсь частині позиції не нульовий байт то пишемо на вихід його інакше пишемо нуль
Функція merge_part приймає масив потоків streams_in з яких читає частину розміром buffer_length і повертає результат злиття частин із різних потоків.
function merge_part(streams_in, buffer_length)
local out_part
for _, stream in ipairs(streams_in) do
local in_part = stream:read(buffer_length)
if not out_part then
out_part = in_part -- просто копируем часть из первого файла
elseif in_part and #in_part > 0 then
if #out_part < #in_part then
out_part, in_part = in_part, out_part
end
if out_part ~= in_part -- данные различаются
and in_part:find("[^ ]") -- есть данные в in_part
and out_part:find(" ", 1, true) -- есть пустые места в out_part
then
local find_index = 1
--[[
Функція string.gsub підходить для завдання оскільки знайде шматочки заповнені нулями і поставить те, що передано їй.
--]]
out_part = out_part:gsub(" +", function(zero_string)
if #in_part < find_index then
return -- не на что менять
end
--[[
string.gsub не передає позицію у якій було знайдено збіг. Тому робимо паралельний пошук позиції zero_string за допомогою функції string.find. Достатньо знайти перший нульовий байт.
Тепер якщо у in_part є дані для out_part копіюємо їх.
--]]
if #in_part >= start_index then
local end_index = start_index + #zero_string - 1
--[[
Вирізаємо з in_part частину відповідну послідовності нулів.
--]]
local part = in_part:sub(start_index, end_index)
if (part:byte(1) ~= 0) or part:find("[^ ]") then
--[[
В part є дані.
--]]
if #part == #zero_string then
return part
else
--[[
part виявився меншим ніж послідовність нулів. Доповнюємо його ними.
--]]
return part..zero_string:sub(1, end_index - #in_part)
end
end
end
end)
end
end
end
return out_part
end
Висновок
Таким чином вдалося завантажити та зібрати цей файл на ПК. Після злиття я витягнув з планшета файл торрент. Встановив на ПК торент клієнт і перевірив їм файл.
Останню завантажену частину на планшеті можна залишити на роздачі, але потрібно включити перед цим повторну перевірку частин і зняти галочку з файлу, щоб він заново не скачувався.