Показать полную графическую версию : [решено] Удалить первый байт в файле
Приветствую!
Задача следующая: нужно удалить первый байт в файле. Этот процесс нужно автоматизировать, поскольку этот байт мне нужно удалить более чем в сотне файлов. Так что если на выходе получится скрипт, который опрашивает директорию с субдиректориями, и все находящиеся в них файлы смещает на один байт вверх, уничтожая этот байт, было бы идеально. Если имена конечных файлов слегка изменятся (например, к имени прибавится цифра 1), это не принципиально.
Foreigner
30-04-2021, 21:43
Как-то так (pwsh.exe)
foreach ($file in (Get-Childitem -File -Recurse))
{
(Get-Content $file -AsByteStream -Raw)[1..($file.length-1)] | Set-Content $file -AsByteStream
}
Foreigner, я совсем не рублю в PowerShell. Попробовал создать скрипт *.ps1, куда записал эти строки. Поместил скрипт в папку с файлами и запустил. Скрипт выдал ошибку и закрылся.
Что я сделал не так?
DJ Mogarych
30-04-2021, 22:45
ошибку »
Какую?
Вставьте в начало скрипта
cd "путь к нужной папке"
и скрипт в папку не помещайте, он же у себя тоже будет пытаться байт откусить.
Foreigner
01-05-2021, 00:01
Любой язык »
Что я сдела не так? »
Тогда попробуйте в таком виде (для powershell.exe)
foreach ($file in (Get-Childitem -File -Recurse))
{
(Get-Content $file -Encoding byte -Raw)[1..($file.length-1)] | Set-Content $file -Encoding byte
}
Это два взаимоисключающих варианта, первый только для pwsh, второй только для powershell.
У меня не было возможности проверить этот.
первый только для pwsh, второй только для powershell. »
можно так:
$root = 'd:\test'
dir $root -file -rec|%{
$bytes = [io.file]::readallbytes($_.fullname)
[io.file]::writeallbytes($_.fullname, $bytes[1..($bytes.count-1)])
}
Наверное надо было уточнить... Пробую все это делать на семерке. Если нужно обязательно на десятке, то скажите, переключусь на нее.
Все скрипты вываливаются с ошибкой. С какой, сказать не могу, так как консольное окно сразу закрывается. Только и успеваю увидеть красный цвет надписи. С файлами в папке ничего не происходит. Еще раз прошу прощения за свою дурость, но с PowerShell я ранее дел не имел.
Коллеги, судя по:
…с PowerShell я ранее дел не имел. »
— вероятно, надо разрешить исполнение неподписанных локальных скриптов.
Iska, насколько я помню, в свое время я давал разрешение командой Set-ExecutionPolicy Unrestricted. Сейчас на всякий случай повторил. Результат не изменился...
Перешел на десятку. Скрипт ниже сработал, но не до конца. Не смог обработать файлы во вложенных папках. Выдал ошибку. В корневой для скрипта директории все обработал.
cd d:\test
foreach ($file in (Get-Childitem -File -Recurse))
{
(Get-Content $file -Encoding byte -Raw)[1..($file.length-1)] | Set-Content $file -Encoding byte
}
А вот скрипт, что представлен ниже, выдал тот результат, что мне нужно!
$root = 'd:\test'
dir $root -file -rec|%{
$bytes = [io.file]::readallbytes($_.fullname)
[io.file]::writeallbytes($_.fullname, $bytes[1..($bytes.count-1)])
}
Благодарю всех за предложенные варианты!!!
Тему считаю исчерпанной.
Только и успеваю увидеть красный цвет надписи. »
Скрипт можно выполнить непосредственно в консоли, тогда она не будет закрыта и ошибку можно будет и прочитать, и скопировать.
YuS_2, не знал про это. Привык, что в cmd в консоль перенести готовый сценарий нельзя...
Ваш скрипт на семерке выдавал такую ошибку:
Get-ChildItem : Не удается найти параметр, соответствующий имени параметра "file".
строка:1 знак:16
+ dir $root -file <<<< -rec|%{
+ CategoryInfo : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Get-ChildItem : Не удается найти параметр, соответствующий имени параметра "file".
строка:6 знак:16
+ dir $root -file <<<< -rec|%{
+ CategoryInfo : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
DJ Mogarych
01-05-2021, 08:54
Судя по всему, у вас старый Powershell. Проверяется командой
host
Его можно обновить до версии 5.1
https://docs.microsoft.com/ru-ru/powershell/scripting/windows-powershell/wmf/setup/install-configure?view=powershell-7.1
Не удается найти параметр, соответствующий имени параметра "file". »
Это значит, что версия powershell 2.0, её надо обновить до 5.1, либо вместо параметра -file, в первом командлете, добавить в конвейер:
|?{!$_.PSIsContainer}
т.е. в целом, код выглядеть будет так:
$root = 'd:\test'
dir $root -rec|?{!$_.PSIsContainer}|%{
$bytes = [io.file]::readallbytes($_.fullname)
[io.file]::writeallbytes($_.fullname, $bytes[1..($bytes.count-1)])
}
DJ Mogarych, YuS_2, совершенно верно. Версия 2.0. Обновил до 5.1 и скрипты заработали корректно на семерке. Спасибо!
Задача не разовая, увы. »
Ну тогда, как-то так:
param (
[string]$folder = '.\TEST'
)
function RW-Stream {
param (
[Parameter(ValueFromPipeline)]
[ValidateNotNullOrEmpty()]
$filein,
$fileout = 'tmp.tmp'
)
begin {
new-variable -name block -val 524288
$buf = new-object byte[] ($block)
}
process {
#measure-command{
$reader = [io.streamreader]::new($filein.fullname)
$writer = [io.streamwriter]::new($fileout)
$reader.basestream.position = 1
while ($reader.basestream.position -lt $reader.basestream.length){
$cnt = $reader.basestream.read($buf,0,$block)
$writer.basestream.write($buf,0,$cnt)
}
$reader.dispose();$writer.dispose()
$reader.close();$writer.close()
mi $fileout $filein.fullname -force
#}
}
}
dir $folder -file -rec|rw-stream
- скрипт принимает в качестве параметра наименование корневого каталога (можно указать абсолютный путь).
Корневой каталог сканируется рекурсивно. Целевые файлы заменяют исходные, то бишь копии нигде не создаются, поэтому применять осторожно, если исходные файлы потребуются в неизменном виде.
Файл ~250Мб, обрабатывается:
TotalSeconds : 7,5637454
Файл ~4,2Гб, обрабатывается:
TotalSeconds : 145,7682588
YuS_2, рекурсивно получаю ошибку:
You cannot call a method on a null-valued expression.
At E:\Design&Graphics\Unpack\onebyte.ps1:22 char:4
+ $cnt = $reader.basestream.read($buf,0,$block)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Единственное, что менял в скрипте, это ".\TEST" заменил на "c:\test"
рекурсивно получаю ошибку »
Всё время забываю проверить на powershell v5.1, тестирую на pwsh 7.2, а у них есть различия...
В общем, там строчку надо удалить было
$filein = gi $filein
- она была нужна из расчета на то, чтобы в функцию можно было вместо объекта передавать строку с путем... но в варианте с командлетом Get-ChildItem (dir), она не критична и не нужна...
- в общем, тут в скрипте (http://forum.oszone.net/post-2970715-16.html) я уже исправил
YuS_2, честно говоря, я слегка в шоке! По скорости обработки этот скрипт по сравнению с прошлым, это как небо и земля. Спасибо огромное!
P.S. А можно на всякий случай еще скрипт со строчкой "$filein = gi $filein"? Когда-нибудь перейду на десятку, а там уже версия PowerShell будет актуальной.
Когда-нибудь перейду на десятку, а там уже версия PowerShell будет актуальной. »
Дык, pwsh v7.2 можно установить и на семерку (он вполне портабелен)... и они будут параллельно работать, не мешая друг другу...
на всякий случай еще скрипт со строчкой "$filein = gi $filein"? »
Эта строка была, вот перед этой:
$reader = [io.streamreader]::new($filein.fullname)
Там можно условие добавить с проверкой версии powershell и не удалять её
Но, по сути, эта строка работала бы в случае вот такого вызова функции
rw-stream "d:\folder\file.ext"
то бишь, без неё вполне можно обойтись, просто в параметр вызова не давать строку, а сразу объект, например так:
$obj = gi "d:\folder\file.ext"
rw-stream $obj
и всё будет функционировать без этой строки...
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.