Сериализация и десериализация файла в электронной таблице - PullRequest
0 голосов
/ 15 марта 2019

Я чувствую себя грязно, спрашивая об этом, потому что это такой хакерский обходной путь, но у меня есть проект, в котором результат должен быть одним файлом .xlsm.Тем не менее, у нас нет никаких ограничений на то, какие файлы этот результат может записывать или выполнять.VBA и редактор макросов Excel имеют ограничения, которые не работают с проектом.

Поэтому я пытаюсь сохранить двоичные значения интерпретатора Python в листе, а затем записать этот .exe на компьютер клиента, когдамакрос запускается(Я знаю, что это в значительной степени вирус и плохая идея, но требования строги и неизменны.)

У меня есть макрос для чтения python.exe на листе:

Function ReadFromFile(path)

    Dim bytes() As Byte
    Dim fileInt As Integer: fileInt = FreeFile
    Open path For Binary Access Read As #fileInt
    ReDim bytes(0 To LOF(fileInt) - 1)
    Get #fileInt, , bytes
    Close #fileInt

    Set ReadFromFile = bytes

End Function


Sub ReadCompiler_Click()

    Dim path As String: path = ActiveWorkbook.path & "\python.exe.original"
    Dim bytes() As Byte
    bytes = ReadFromFile(path)

    Dim cell As Range
    Set cell = Worksheets("PythonEXE").Range("A1")

    For Each chunk In bytes
        cell.Value = chunk
        Set cell = cell.Offset(1, 0)
    Next chunk

End Sub

Я подтвердил, что это копирует побайтный файл двоичного файла в столбец A моего PythonEXE листа.

Моя проблема заключается в том, что при записи байтов обратно в файл записанный файл значительно отличается оторигинал.Я использую следующие функции для записи из рабочей таблицы в выходной файл:

Function WriteToFile(path, data)

    Dim fileNo As Integer
    fileNo = FreeFile

    Open path For Binary Access Write As #fileNo

    Put #fileNo, 1, data    

    Close #fileNo

End Function

Sub WriteCompiler_Click()

    Dim TotalRows As Long
    Dim bytes() As Byte

    TotalRows = Worksheets("PythonEXE").Rows(Worksheets("PythonEXE").Rows.Count).End(xlUp).Row
    ReDim bytes(TotalRows)

    For i = 1 To TotalRows
        bytes(i) = CByte(Worksheets("PythonEXE").Cells(i, 1).Value)
    Next i

    Dim path As String: path = ActiveWorkbook.path & "\python.exe.written"
    WriteToFile path, bytes

End Sub


Почему мой выходной двоичный файл отличается от входного двоичного файла?Он не читается человеком, но их контрольные суммы различаются, и когда я открываю их обе в IDE, выходной файл выглядит так, как будто в начале он имеет кучу прямоугольных глифов, а входной файл - нет.

1 Ответ

0 голосов
/ 16 марта 2019

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

  1. Когда VBA записывает Variant, он выводит некоторую информацию заголовка в вывод. Поэтому я изменил WriteToFile, чтобы скопировать data в массив Byte перед записью:
Dim buffer() As Byte
ReDim buffer(UBound(data))
buffer = data
For i = 0 To UBound(data)
        Put #fileNo, i + 1, CByte(buffer(i))
Next i
  1. У меня возникла ошибка, когда я перешел на UBound (данные) вместо UBound (данные) - 1. Это немного странно, потому что Put принимает позицию записи как единичную, а не нулевую , но индексаторы массива начинаются с нуля:
Dim buffer() As Byte
ReDim buffer(UBound(data))
buffer = data
For i = 0 To (UBound(data) - 1)
        Put #fileNo, i + 1, CByte(buffer(i))
Next i

Вот полное решение:

Function WriteToFile(path, data)

    Dim fileNo As Integer
    fileNo = FreeFile

    Open path For Binary Access Write As #fileNo

    Dim buffer() As Byte
    ReDim buffer(UBound(data))
    buffer = data
    For i = 0 To (UBound(data) - 1)
        Put #fileNo, i + 1, CByte(buffer(i))
    Next i

    Close #fileNo

'    Shell ("explorer.exe " & path)

End Function


Function ReadFromFile(path)

    Application.StatusBar = "Reading " & path

    Dim bytes() As Byte
    Dim fileInt As Integer: fileInt = FreeFile
    Open path For Binary Access Read As #fileInt
    ReDim bytes(0 To LOF(fileInt) - 1)
    Get #fileInt, , bytes
    Close #fileInt

    ReadFromFile = bytes

End Function

Sub UpdatePython_Click()

    Application.Calculation = xlCalculationManual

    Dim path As String: path = ActiveWorkbook.path & "\python.exe.original"
    Dim bytes() As Byte
    bytes = ReadFromFile(path)

    Worksheets("PythonEXE").Columns(1).EntireColumn.Clear

    Dim cell As range
    Set cell = Worksheets("PythonEXE").range("A1")

    For Each chunk In bytes
        cell.Value = chunk
        Set cell = cell.Offset(1, 0)
    Next chunk

    Application.ActiveWorkbook.Save

    Application.Calculation = xlCalculationAutomatic

End Sub


Sub WriteCompiler_Click()

    Dim TotalRows As Long
    Dim bytes() As Byte

    TotalRows = Worksheets("PythonEXE").Rows(Worksheets("PythonEXE").Rows.Count).End(xlUp).Row
    ReDim bytes(TotalRows)

    For i = 0 To TotalRows
        bytes(i) = CByte(Worksheets("PythonEXE").Cells(i + 1, 1).Value)
    Next i

    Dim path As String: path = ActiveWorkbook.path & "\python.exe.written"
    If Dir(path) <> "" Then
        Kill path
    End If
    WriteToFile path, bytes

    Shell ActiveWorkbook.path & "\checksum.bat", vbNormalFocus

End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...