Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Удалить последний байт в файле (http://forum.oszone.net/showthread.php?t=291932)

pzh2393 01-12-2014 19:34 2438166

Удалить последний байт в файле
 
Прошу помощи в написании скрипта который позволил бы удалить (отрезать) последний байт в файле.

Немного объясню.. есть у меня группа JPEG файлов (порядка полтысячи) у которых по непонятной мне причине в конец дописан символ перевода строки А0.
В принципе с этим жить можно, но вот при поиске дубликатов из-за этой разницы получаю не тот результат на который рассчитывал.
Использовать утилиты проверяющие по содержимому (т.е. более долго) пока не хочется, проще у найденных вырезать "лишний" байт в конце.
Очень прошу помочь со скриптом.

Iska 02-12-2014 06:02 2438362

На 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» — они будут урезаны по размеру на этот последний байт. Вложенные папки не обрабатываются. Резервных копий исходных файлов не делается.

Iska 02-12-2014 06:49 2438372

Примерный аналог на 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» не включён по умолчанию :(.

pzh2393 02-12-2014 12:46 2438552

Цитата:

Цитата Iska
На WSH: »

Спасибо!
Только при перетаскивании на скрипт выбивает окно с ошибкой "There is no script file specified".


На PowerShell работает нормально, но как-то не удобно каждый раз вручную менять путь в "[string]$sSourceFolder = "E:\..."


P.S. Было бы очень желательно если бы скрипт запускался не перетаскиванием папки, а обычным "двойным щелчком".

Iska 02-12-2014 13:04 2438560

Цитата:

Цитата pzh2393
Только при перетаскивании на скрипт выбивает окно с ошибкой "There is no script file specified". »

Сохраните не с расширеним «.wsh», а с расширением «.vbs».

Цитата:

Цитата pzh2393
На PowerShell работает нормально, но как-то не удобно каждый раз вручную менять путь в "[string]$sSourceFolder = "E:\..."
»

Верю. Но у меня перетаскивание с типом «.ps1» не работает. А у Вас?

Цитата:

Цитата pzh2393
P.S. Было бы очень желательно если бы скрипт запускался не перетаскиванием папки, а обычным "двойным щелчком". »

А дальше? Откуда брать имя целевой папки? Запрашивать каждый раз? Поверьте, это куда неудобнее.

pzh2393 02-12-2014 14:12 2438592

Спасибо Iska.

А можно ещё попросить вариант скрипта на WSH срабатывающего только для одного файла а не для всей папки?
имя файла будет передаваться командой "cut.vbs %1"

Iska 02-12-2014 14:27 2438595

Как-то так:
Скрытый текст
Код:

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


Аналогично можно перетаскивать файл на скрипт.

Iska 06-12-2014 15:14 2440355

Из письма в 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
}


pzh2393 06-12-2014 15:51 2440372

А что-то вроде этого на 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


скриптописец конечно из меня "нулевой", но может все же имеет смысл?

Iska 06-12-2014 19:07 2440451

Цитата:

Цитата 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


pzh2393 06-12-2014 19:28 2440459

Премного благодарен!
Отлично работает!
А то я даже начал потихоньку самостоятельно пробовать..
Правда у меня Do Loop While почему-то срабатывало таким образом, что "срезали" тестовый файл до нуля, а затем он как бы создавался по новой и всё начиналось заново, до тех пор пока не выгрузишь процесс из задач. :dont-know


Время: 10:39.

Время: 10:39.
© OSzone.net 2001-