Удалить последний байт в файле
Прошу помощи в написании скрипта который позволил бы удалить (отрезать) последний байт в файле.
Немного объясню.. есть у меня группа JPEG файлов (порядка полтысячи) у которых по непонятной мне причине в конец дописан символ перевода строки А0.
В принципе с этим жить можно, но вот при поиске дубликатов из-за этой разницы получаю не тот результат на который рассчитывал.
Использовать утилиты проверяющие по содержимому (т.е. более долго) пока не хочется, проще у найденных вырезать "лишний" байт в конце.
Очень прошу помочь со скриптом.
|
На WSH:
Скрытый текст
Код:
Option Explicit
Const adTypeBinary = 1
Const adSaveCreateOverWrite = 2
Dim strSourceFolder
Dim objFile
If WScript.Arguments.Count = 1 Then
strSourceFolder = WScript.Arguments.Item(0)
With WScript.CreateObject("Scripting.FileSystemObject")
If .FolderExists(strSourceFolder) Then
For Each objFile In .GetFolder(strSourceFolder).Files
Select Case LCase(.GetExtensionName(objFile.Name))
Case "jpg", "jpeg", "jpe"
With WScript.CreateObject("ADODB.Stream")
.Type = adTypeBinary
.Open
.LoadFromFile objFile.Path
.Position = objFile.Size - 1
If AscB(MidB(.Read(1), 1, 1)) = &H0A Then
.Position = objFile.Size - 1
.SetEOS
.SaveToFile objFile.Path, adSaveCreateOverWrite
End If
.Close
End With
Case Else
' Nothing to do
End Select
Next
Else
WScript.Echo "Can't find source folder [" & strSourceFolder & "]."
WScript.Quit 2
End If
End With
Else
WScript.Echo "Usage: " & WScript.ScriptName & " <Source folder>"
WScript.Quit 1
End If
WScript.Quit 0
Достаточно просто перетащить целевую папку на скрипт. Будут найдены все файлы в этой папке с расширениями "jpg", "jpeg", "jpe", и, если содержимым их последнего байта окажется «0x0A» — они будут урезаны по размеру на этот последний байт. Вложенные папки не обрабатываются. Резервных копий исходных файлов не делается.
|
Примерный аналог на PowerShell (в качестве самообучения):
Скрытый текст
Код:
Param(
[string]$sSourceFolder = "E:\Песочница\0411"
)
if(Test-Path -Path $sSourceFolder -PathType Container) {
Get-ChildItem -Path $sSourceFolder -Recurse -Include "*.jpg", "*.jpeg", "*.jpe" |`
Where-Object -FilterScript {
-not $_.PSIsContainer
} | ForEach-Object -Process {
$oFileStream = $_.Open([System.IO.FileMode]::Open)
[void]$oFileStream.Seek(-1, [System.IO.SeekOrigin]::End)
if($oFileStream.ReadByte() -eq 0x0A) {
Write-Host "* $($_.Name)" -ForegroundColor Green
$oFileStream.SetLength($oFileStream.Position - 1)
} else {
Write-Host " $($_.Name)"
}
$oFileStream.Close()
$oFileStream.Dispose()
}
} else {
Write-Host "Can't find source folder [$sSourceFolder]." -ForegroundColor Red
}
P.S. Внезапно обнаружил, что Drag-n-Drop на «.ps1» не включён по умолчанию :(.
|
Спасибо!
Только при перетаскивании на скрипт выбивает окно с ошибкой "There is no script file specified".
На PowerShell работает нормально, но как-то не удобно каждый раз вручную менять путь в "[string]$sSourceFolder = "E:\..."
P.S. Было бы очень желательно если бы скрипт запускался не перетаскиванием папки, а обычным "двойным щелчком".
|
Цитата:
Цитата pzh2393
Только при перетаскивании на скрипт выбивает окно с ошибкой "There is no script file specified". »
|
Сохраните не с расширеним «.wsh», а с расширением «.vbs».
Цитата:
Цитата pzh2393
На PowerShell работает нормально, но как-то не удобно каждый раз вручную менять путь в "[string]$sSourceFolder = "E:\..."
»
|
Верю. Но у меня перетаскивание с типом «.ps1» не работает. А у Вас?
Цитата:
Цитата pzh2393
P.S. Было бы очень желательно если бы скрипт запускался не перетаскиванием папки, а обычным "двойным щелчком". »
|
А дальше? Откуда брать имя целевой папки? Запрашивать каждый раз? Поверьте, это куда неудобнее.
|
Спасибо Iska.
А можно ещё попросить вариант скрипта на WSH срабатывающего только для одного файла а не для всей папки?
имя файла будет передаваться командой "cut.vbs %1"
|
Как-то так:
Скрытый текст
Код:
Option Explicit
Const adTypeBinary = 1
Const adSaveCreateOverWrite = 2
Dim strSourceFile
Dim objFile
If WScript.Arguments.Count = 1 Then
strSourceFile = WScript.Arguments.Item(0)
With WScript.CreateObject("Scripting.FileSystemObject")
If .FileExists(strSourceFile) Then
Set objFile = .GetFile(strSourceFile)
Select Case LCase(.GetExtensionName(objFile.Name))
Case "jpg", "jpeg", "jpe"
With WScript.CreateObject("ADODB.Stream")
.Type = adTypeBinary
.Open
.LoadFromFile objFile.Path
.Position = objFile.Size - 1
If AscB(MidB(.Read(1), 1, 1)) = &H0A Then
.Position = objFile.Size - 1
.SetEOS
.SaveToFile objFile.Path, adSaveCreateOverWrite
Else
WScript.Echo "Last byte of source file [" & strSourceFile & "] is not a 0x0A value."
End If
.Close
End With
Case Else
WScript.Echo "Source file [" & strSourceFile & "] probably not a jpeg file."
WScript.Quit 3
End Select
Else
WScript.Echo "Can't find source file [" & strSourceFile & "]."
WScript.Quit 2
End If
End With
Else
WScript.Echo "Usage: " & WScript.ScriptName & " <Source file>"
WScript.Quit 1
End If
WScript.Quit 0
Аналогично можно перетаскивать файл на скрипт.
|
Из письма в PM:
Скрытый текст
Цитата:
Цитата pzh2393
Добрый день!
Прошу прощения, что обращаюсь напрямую, но восстанавливать эту тему ( http://forum.oszone.net/thread-291932.html) считаю не имеет смысла.
Оказалось, что часть из моих файлов в конце содержат не только символ перевода строки, но и ряд других, включая просто "обнуленные" (00 00 00 00...) последовательности непостоянного размера.
Можно ли подредактировать скрипт таким образом, чтобы удалялся не только последний байт, а все лишние от конца вплоть до FF D9 (по спецификации конец JPEG файла) ?
Прошу помочь, поскольку в скриптописании (особенно на WHS) не силен.
|
Именно что имеет смысл. Надо было писать именно здесь, и затем, если очень хочется, дать ссылку на новое сообщение в PM.
Поскольку непосредственная работа с ByteArray в WSH не предусмотрена — наш выбор PowerShell:
Скрытый текст
Код:
Param(
[string]$sSourceFolder = "E:\Песочница\0411"
)
if(Test-Path -Path $sSourceFolder -PathType Container) {
Get-ChildItem -Path $sSourceFolder -Recurse -Include "*.jpg", "*.jpeg", "*.jpe" |`
Where-Object -FilterScript {
-not $_.PSIsContainer
} | ForEach-Object -Process {
$oFileStream = $_.Open([System.IO.FileMode]::Open)
[void]$oFileStream.Seek(-2, [System.IO.SeekOrigin]::End)
if($oFileStream.ReadByte() -eq 0xFF -and $oFileStream.ReadByte() -eq 0xD9) {
Write-Host " $($_.Name)"
} else {
$bFound = $false
for($i = $oFileStream.Length - 3; $i -ge 0; $i--) {
[void]$oFileStream.Seek($i, [System.IO.SeekOrigin]::Begin)
if($oFileStream.ReadByte() -eq 0xFF -and $oFileStream.ReadByte() -eq 0xD9) {
$oFileStream.SetLength($oFileStream.Position)
$bFound = $true
break
}
}
if($bFound) {
Write-Host "* $($_.Name)" -ForegroundColor Green
} else {
Write-Host " $($_.Name)" -ForegroundColor Red
}
}
$oFileStream.Close()
$oFileStream.Dispose()
}
} else {
Write-Host "Can't find source folder [$sSourceFolder]." -ForegroundColor Red
}
|
А что-то вроде этого на WSH не сработает?
Скрытый текст
Код:
Option Explicit
Const adTypeBinary = 1
Const adSaveCreateOverWrite = 2
Dim strSourceFolder
Dim objFile
If WScript.Arguments.Count = 1 Then
strSourceFolder = WScript.Arguments.Item(0)
With WScript.CreateObject("Scripting.FileSystemObject")
If .FolderExists(strSourceFolder) Then
For Each objFile In .GetFolder(strSourceFolder).Files
Select Case LCase(.GetExtensionName(objFile.Name))
Case "jpg", "jpeg", "jpe"
With WScript.CreateObject("ADODB.Stream")
.Type = adTypeBinary
.Open
.LoadFromFile objFile.Path
.Position = objFile.Size - 1
If AscB(MidB(.Read(1), 1, 1)) = &HD9 Then
' Nothing to do
Else
.Position = objFile.Size - 1
.SetEOS
.SaveToFile objFile.Path, adSaveCreateOverWrite
End If
.Close
End With
Case Else
' Nothing to do
End Select
Next
Else
WScript.Echo "Can't find source folder [" & strSourceFolder & "]."
WScript.Quit 2
End If
End With
Else
WScript.Echo "Usage: " & WScript.ScriptName & " <Source folder>"
WScript.Quit 1
End If
WScript.Quit 0
скриптописец конечно из меня "нулевой", но может все же имеет смысл?
|
Цитата:
Цитата pzh2393
А что-то вроде этого на WSH не сработает? »
|
Вы и мёртвого уговорите. Пробуйте:
Скрытый текст
Код:
Option Explicit
Const adTypeBinary = 1
Const adSaveCreateOverWrite = 2
Dim strSourceFolder
Dim objFile
Dim i
If WScript.Arguments.Count = 1 Then
strSourceFolder = WScript.Arguments.Item(0)
With WScript.CreateObject("Scripting.FileSystemObject")
If .FolderExists(strSourceFolder) Then
For Each objFile In .GetFolder(strSourceFolder).Files
Select Case LCase(.GetExtensionName(objFile.Name))
Case "jpg", "jpeg", "jpe"
With WScript.CreateObject("ADODB.Stream")
.Type = adTypeBinary
.Open
.LoadFromFile objFile.Path
.Position = objFile.Size - 2
If AscB(MidB(.Read(1), 1, 1)) = &HFF And AscB(MidB(.Read(1), 1, 1)) = &HD9 Then
' Nothing to do
Else
For i = .Size - 3 To 0 Step -1
.Position = i
If AscB(MidB(.Read(1), 1, 1)) = &HFF And AscB(MidB(.Read(1), 1, 1)) = &HD9 Then
.SetEOS
.SaveToFile objFile.Path, adSaveCreateOverWrite
Exit For
End If
Next
End If
.Close
End With
Case Else
' Nothing to do
End Select
Next
Else
WScript.Echo "Can't find source folder [" & strSourceFolder & "]."
WScript.Quit 2
End If
End With
Else
WScript.Echo "Usage: " & WScript.ScriptName & " <Source folder>"
WScript.Quit 1
End If
WScript.Quit 0
|
Премного благодарен!
Отлично работает!
А то я даже начал потихоньку самостоятельно пробовать..
Правда у меня Do Loop While почему-то срабатывало таким образом, что "срезали" тестовый файл до нуля, а затем он как бы создавался по новой и всё начиналось заново, до тех пор пока не выгрузишь процесс из задач. :dont-know
|
Время: 10:39.
© OSzone.net 2001-