Base64 (как получить приемлимую скорость)

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 25.10.2009 (Вс) 11:34

Всем привет!

Давно не писал, был занят. Недавно столкнулся с необходимостью отправить файл на сервер в автоматическом режиме. Сделал формочку, распарсил посмотрел закинул в WinHTTP и бамс ... сервер говорит что я формочку не отправил:) а длина данных вместо 400к всего 182 байта. Вообщем стал разбираться оказывается проблема была в пресловутых нулевых байтах которые были в бинариках отправляемых на сервер. Пришлось обратиться к манулу на тему как закодировать так, чтобы проходил.
Здесь нашел ответ - Base64, взял свой древний алгоритм (прилагать его не буду чтоб не дискридитировать себя, суть была в привидении 3*ASC => 24*BIN => 4*ASC), запустил ... ждал минуты 3 пока файл перекодируется, перекодировался, прошел. В принципе на этом можно было бы и закончить пост, но ждать 3 минуты - мне не понравилось. Начал искать, нашел вариант в сети - там я ждал 18 секунд, это уже было значительно интереснее по сравнению с 3 минутами, но всеже как-то медленно)) Решил разложить всё с нуля.

в форме решил потестировать различные варианты:
базовая идея преобразования заключалась в данном коде:
Код: Выделить всё
    B(1) = Mid$(IncStr,I,1)
    B(2) = Mid$(IncStr,I + 1,1)
    B(3) = Mid$(IncStr,I + 2,1)
    'результирующая последовательность
    R(1) = B(1) \ 4
    R(2) = (B(1) Mod 4) * 16 + B(2) \ 16
    R(3) = (B(2) Mod 16) * 4 + B(3) \ 64
    R(4) = B(3) Mod 64
    Res = Res & Mid$(Code,R(1),1) & Mid$(Code,R(2),1) & Mid$(Code,R(3),1) & Mid$(Code,R(4),1)


всё конечно получилось, только вот 100000 байт считывало 7 секунд, рисковать и проверять на 1Мб не решился)))
требовалось немного ускорить, в противном случае это грозило минутным ожиданием при отправке фотографии в 1М на сайт (только лишь на перекодировку).

Вообщем решил пойти по пути поэтапной оптимизации на форме для тестирования:
на форме кнопка, вот код:

Код: Выделить всё
Dim A1 As Single
Dim A2 As Single
Dim A3 As Single
Dim A4 As Single
Dim SMB As String
Const N = 1048576
Dim ARR(63) As Byte
Private Const Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

Private Sub Form_Load()
  Erase ARR
  For I = 0 To 63
    ARR(I) = Asc(Mid$("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", I + 1, 1))
  Next I
End Sub

Function Base64Encode2(ByRef ArrByte() As Byte) As String
  Dim ResByte() As Byte
  Dim B(3) As Byte
  Dim R(4) As Byte
  Dim DobSmb As Byte
  Dim I As Long
  Dim F As Long
  Dim T As Long
  DobSmb = (3 - (UBound(ArrByte) Mod 3)) Mod 3
  ReDim Preserve ArrByte(UBound(ArrByte) + DobSmb)
  F = UBound(ArrByte) \ 3
  ReDim ResByte(UBound(ArrByte) / 3 * 4)
  'IncStr = IncStr & String(DobSmb, 0)
  For I = 1 To UBound(ArrByte) Step 3
    B(1) = ArrByte(I)
    B(2) = ArrByte(I + 1)
    B(3) = ArrByte(I + 2)
    R(1) = B(1) \ 4
    R(2) = (B(1) Mod 4) * 16 + B(2) \ 16
    R(3) = (B(2) Mod 16) * 4 + B(3) \ 64
    R(4) = B(3) Mod 64
    T = ((I - 1) \ 3) * 4
    If F = (I + 2) \ 3 Then
      ResByte(T + 1) = ARR(R(1))
      ResByte(T + 2) = ARR(R(2))
      Select Case DobSmb
        Case 0:
          ResByte(T + 3) = ARR(R(3))
          ResByte(T + 4) = ARR(R(4))
        Case 1:
          ResByte(T + 3) = ARR(R(3))
          ResByte(T + 4) = 61
        Case 2:
          ResByte(T + 3) = 61
          ResByte(T + 4) = 61
      End Select
    Else
      ResByte(T + 1) = ARR(R(1))
      ResByte(T + 2) = ARR(R(2))
      ResByte(T + 3) = ARR(R(3))
      ResByte(T + 4) = ARR(R(4))
    End If
  Next I
  Base64Encode2 = ResByte
End Function

Private Sub Command1_Click()
  Dim ArrByte() As Byte
  A1 = Timer
  SMB = String(N, "A")
  A2 = Timer
  ArrByte = SMB
  A3 = Timer
  RES = Base64Encode2(ArrByte)
  A4 = Timer
  Erase ArrByte
  Debug.Print "#2:", A2 - A1, A3 - A2, A4 - A3, A4 - A1
End Sub


вот результат тестирования из окна отладки:
Код: Выделить всё
#2:            0             0             1,09375       1,09375
#2:            0             0,015625      1,09375       1,109375
#2:            0             0             1,09375       1,09375
#2:            0             0             1,09375       1,09375
#2:            0             0             0,84375       0,84375
#2:            0,015625      0             1,09375       1,109375
#2:            0,015625      0             1,09375       1,109375
#2:            0             0,015625      1,09375       1,109375


здесь видно что для прогона 1МБ потребовалось лишь от 0,84 до 1,093, этот результат мне понравился, возник лишь вопрос, а можно ли сделать быстрее? Как мне показалось - Да, можно. Попробовал избавиться от массивов R и B заменив их переменными R1..R4,B1..B3

получилось вот так:
Код: Выделить всё
Function Base64Encode(ByRef ArrByte() As Byte) As String
  Dim ResByte() As Byte
  Dim B1 As Byte
  Dim B2 As Byte
  Dim B3 As Byte
  Dim R1 As Byte
  Dim R2 As Byte
  Dim R3 As Byte
  Dim R4 As Byte
  Dim DobSmb As Byte
  Dim I As Long
  Dim F As Long
  Dim T As Long
 
 
  DobSmb = (3 - (UBound(ArrByte) Mod 3)) Mod 3
  ReDim Preserve ArrByte(UBound(ArrByte) + DobSmb)
  F = UBound(ArrByte) \ 3
  ReDim ResByte(UBound(ArrByte) / 3 * 4)
 
  'IncStr = IncStr & String(DobSmb, 0)
  For I = 1 To UBound(ArrByte) Step 3
    B1 = ArrByte(I)
    B2 = ArrByte(I + 1)
    B3 = ArrByte(I + 2)
    R1 = B1 \ 4
    R2 = (B1 Mod 4) * 16 + B2 \ 16
    R3 = (B2 Mod 16) * 4 + B3 \ 64
    R4 = B3 Mod 64
    T = ((I - 1) \ 3) * 4
    If F = (I + 2) \ 3 Then
      ResByte(T + 1) = ARR(R1)
      ResByte(T + 2) = ARR(R2)
      Select Case DobSmb
        Case 0:
          ResByte(T + 3) = ARR(R3)
          ResByte(T + 4) = ARR(R4)
        Case 1:
          ResByte(T + 3) = ARR(R3)
          ResByte(T + 4) = 61
        Case 2:
          ResByte(T + 3) = 61
          ResByte(T + 4) = 61
      End Select
    Else
      ResByte(T + 1) = ARR(R1)
      ResByte(T + 2) = ARR(R2)
      ResByte(T + 3) = ARR(R3)
      ResByte(T + 4) = ARR(R4)
    End If
  Next I
  Base64Encode = ResByte
End Function


вот результат из окна отладки:
Код: Выделить всё
#1:            0             0,015625      0,765625      0,78125
#1:            0             0             0,78125       0,78125
#1:            0             0,015625      0,765625      0,78125
#1:            0             0             0,78125       0,78125
#1:            0             0             0,78125       0,78125
#1:            0,015625      0             0,75          0,765625
#1:            0             0             0,78125       0,78125
#1:            0             0             0,53125       0,53125


Результат вдохновил, но можно ли лучше? )))

Прошу помощи)))
Последний раз редактировалось SSecurity 25.10.2009 (Вс) 12:53, всего редактировалось 1 раз.
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 25.10.2009 (Вс) 11:41

получилось сделать вот так:
Код: Выделить всё
#1:            0,015625      0             0,59375       0,609375
#1:            0,015625      0             0,609375      0,625
#1:            0             0,015625      0,59375       0,609375
#1:            0,015625      0             0,59375       0,609375
#1:            0             0             0,40625       0,40625
#1:            0             0,015625      0,59375       0,609375
#1:            0             0,015625      0,59375       0,609375
#1:            0             0,015625      0,59375       0,609375


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

Код: Выделить всё
Function Base64Encode(ByRef ArrByte() As Byte) As String
  Dim ResByte() As Byte
  Dim B1 As Byte
  Dim B2 As Byte
  Dim B3 As Byte
  Dim R1 As Byte
  Dim R2 As Byte
  Dim R3 As Byte
  Dim R4 As Byte
  Dim DobSmb As Byte
  Dim I As Long
  Dim F As Long
  Dim T As Long
 
 
  DobSmb = (3 - (UBound(ArrByte) Mod 3)) Mod 3
  ReDim Preserve ArrByte(UBound(ArrByte) + DobSmb)
  F = UBound(ArrByte) \ 3
  ReDim ResByte(UBound(ArrByte) / 3 * 4)
 
  'IncStr = IncStr & String(DobSmb, 0)
  For I = 1 To UBound(ArrByte) Step 3
    B1 = ArrByte(I)
    B2 = ArrByte(I + 1)
    B3 = ArrByte(I + 2)
    R1 = B1 \ 4
    R2 = (B1 Mod 4) * 16 + B2 \ 16
    R3 = (B2 Mod 16) * 4 + B3 \ 64
    R4 = B3 Mod 64
    T = ((I - 1) \ 3) * 4
    ResByte(T + 1) = ARR(R1)
    ResByte(T + 2) = ARR(R2)
    ResByte(T + 3) = ARR(R3)
    ResByte(T + 4) = ARR(R4)
  Next I
  Select Case DobSmb
    Case 1:
      ResByte(T + 3) = ARR(R3)
      ResByte(T + 4) = 61
    Case 2:
      ResByte(T + 3) = 61
      ResByte(T + 4) = 61
  End Select
  Base64Encode = ResByte
End Function
Последний раз редактировалось SSecurity 25.10.2009 (Вс) 12:58, всего редактировалось 1 раз.
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Base64 (как получить приемлимую скорость)

Сообщение Хакер » 25.10.2009 (Вс) 12:31

Дело в том, что в принципе HTTP-протокол не накладывает ограничения на нулевые байты. Так что, если разобраться, можно и не кодировать в b64. С другой стороны, ПО, которые полагается на протокол, может иметь свои ограничения. Но они довольно легко обходятся. Будем развивать разговор в этом направлении?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 25.10.2009 (Вс) 12:47

Хакер приветствую, в принципе можем и в этом направлении поговорить:) Во всяком случае никто не запретит же потом гибридный вариант использовать.

Кстати, судя по логам сервера "опера" именно бинарик и шлет ... а вот у меня бинарик не проходит.
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Base64 (как получить приемлимую скорость)

Сообщение Хакер » 25.10.2009 (Вс) 12:53

Так речь о веб-форме?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 25.10.2009 (Вс) 13:07

Код: Выделить всё
<html>
<body>
<form method=post action="http://localhost/001/upl.php" enctype="multipart/form-data">
<input type="text" name="t" value="m">
<input type="text" name="n" value="0">
<input type="file" NAME="filename">
<input type="submit">
</form>
</body>
</html>


эта сама форма которая оперой посылается, если речь идет о данных без бинариков .... то там все просто ...

собственно если говорить о WinHTTPRequest, то ниже есть код который я использую как юзерконтрол (оптимальнее как класс использовать), но контрол мне пока интереснее, не принципиально.

Код: Выделить всё
Private Function GenerateBoundary() As String
  GenerateBoundary = ""
  'MyBoundary = "------------4rh5YvflFuIFILrr96qFPU"
  Codeline = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"
  While Len(GenerateBoundary) < 20
    GenerateBoundary = GenerateBoundary & Mid(Codeline, Int((Rnd * Len(Codeline)) Mod Len(Codeline) + 1), 1)
  Wend
End Function

Private Function GetFilePack(ByVal fldName As String, ByVal FileName As String, ByVal Boundary As String) As String
  Dim FS As New FileSystemObject
  Dim BUF As String
  Dim MFC As New MailFunc
  Dim dBuffer As String * 50000
  GetFilePack = ""
  If FS.FileExists(FileName) Then
    GetFilePack = "--" & Boundary & vbCrLf
    GetFilePack = GetFilePack & "Content-Disposition: form-data; name=""" & Replace(fldName, """", """""") & """; filename=""" & Replace(FS.GetFileName(FileName), """", """""") & """" & vbCrLf
    GetFilePack = GetFilePack & "Content-Type: application/octet-stream" & vbCrLf
    GetFilePack = GetFilePack & "Content-Transfer-Encoding: binary" & vbCrLf & vbCrLf
   
    A = FreeFile
    'здесь мой кривой способ считывать содержимое файла :)
    Open FileName For Binary As #A
      For i = 0 To FileLen(FileName) \ 50000
        Get #A, i * 50000 + 1, dBuffer
        BUF = BUF & dBuffer
      Next
      BUF = Left$(BUF, FileLen(FileName))
    Close #A
    GetFilePack = GetFilePack & BUF & vbCrLf
  End If
End Function

'это для переменнх формы
Private Function GetFormData(ByVal fldName As String, ByVal Value As String, ByVal Boundary As String) As String
  GetFormData = "--" & Boundary & vbCrLf
  GetFormData = GetFormData & "Content-Disposition: form-data; name=""" & Replace(fldName, """", """""") & """" & vbCrLf & vbCrLf
  GetFormData = GetFormData & Value & vbCrLf
End Function

'сама процедура отправки запроса
Function SendPostWHTTP(ByVal URL As String, ByVal fldName As String, ByVal FilePath As String, SubData As Dictionary, Optional   ByVal locTimeOut As Integer = 60) As String
  Dim MyBoundary As String
  Dim data As String
  MyBoundary = GenerateBoundary
 
  data = vbCrLf & vbCrLf & GetFilePack(fldName, FilePath, MyBoundary)
 
  For Each xValue In SubData
    data = data & GetFormData(xValue, SubData(xValue), MyBoundary)
  Next
  data = data & "--" & MyBoundary & "--" & vbCrLf

  Set WR = New WinHttpRequest
  WR.Open "POST", URL, False
  WR.setRequestHeader "User-Agent", "Opera/9.64 (Windows NT 5.1; U; ru) Presto/2.1.1"
  'WR.setRequestHeader "Host", GetHostFromUrl(URL)
  WR.setRequestHeader "Accept", "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1"
  WR.setRequestHeader "Accept-Language", "ru-RU,ru;q=0.9,en;q=0.8"
  WR.setRequestHeader "Accept-Charset", "iso-8859-1, utf-8, utf-16, *;q=0.1"
  'WR.setRequestHeader "Connection", "Keep-Alive"
  WR.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & MyBoundary & ""
  WR.setRequestHeader "Content-Length", Str(Len(data))
  Open "d:\response.bin" For Output As 1
    Print #1, data
  Close
  WR.send StrConv(data, vbFromUnicode)
  WR.WaitForResponse locTimeOut
  If WR.Status = 200 Then SendPostWHTTP = WR.responseText
End Function


urlencode не пользуюсь, лишь в рамках этой задачи ... (все переменные латинские), но при необходимости введу в класс.
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

awl100Alex
Постоялец
Постоялец
 
Сообщения: 355
Зарегистрирован: 29.01.2008 (Вт) 15:19
Откуда: Украина

Re: Base64 (как получить приемлимую скорость)

Сообщение awl100Alex » 25.10.2009 (Вс) 13:12

SSecurity
Можно ускорить еще в 1,5-2 раза...
Код: Выделить всё
'References --> подключить msxml3.dll (Microsoft XML v3.0)
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetTickCount& Lib "kernel32" ()

Private Sub Form_Load()
Dim A1, A2 As Long
Dim SMB As String
Const N = 1048576
SMB = String(N, "A")
A1 = GetTickCount&
Debug.Print Encode(SMB)
A2 = GetTickCount&
Debug.Print "Время кодирования: " & (A2 - A1) / 1000 & " сек." '1 сек = 1000 мс
End Sub

Public Function Encode(ByVal iStr As String) As String
Dim iXml As New MSXML2.DOMDocument30
Dim iArray() As Byte
    With iXml.createElement("Encoder")
        .dataType = "bin.base64"
        ReDim iArray(LenB(iStr))
        CopyMemory iArray(0), ByVal StrPtr(iStr), LenB(iStr)
        .nodeTypedValue = iArray()
        Encode = .Text
    End With
End Function

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 25.10.2009 (Вс) 13:17

Супер, только бы ещё без сторонних компоненнтов))
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 11:03

Наверно я лошок:)

Если строку перегнать в массив бауйтовый то размер массива у меня получается в 2 раза больше
т.е. "AAAA" = {65,0,65,0,65,0,65,0,0}, следовательно и работать надо с нечетными элемнтами.
это первое, второе - насколько мне известно Base64 множит на 33% длину + переносы строк
т.е. 400000 должно было преобразоваться в в 533333 символа + 7407 переносов строки.
Итого: все вместе максимум 550-560 тыс. байт.
Кодирование MSXML2 мне в итоге дало 1 600 тыс. байт, что насторожило))

наверно правильный метод - это брать нечетные символы - размещать результата в нечетных элементах результирующего массива
а потом сворачивать его до строки.
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

ANDLL
Великий гастроном
Великий гастроном
Аватара пользователя
 
Сообщения: 3450
Зарегистрирован: 29.06.2003 (Вс) 18:55

Re: Base64 (как получить приемлимую скорость)

Сообщение ANDLL » 26.10.2009 (Пн) 13:04

Быстро будет вероятно работать CryptStringToBinary
Гастрономия - наука о пище, о ее приготовлении, употреблении, переварении и испражнении.
Блог

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 13:50

ANDLL писал(а):Быстро будет вероятно работать CryptStringToBinary

0.22 .. 0.32 я уже получил, причем текст уже форматированный (по 72 символа в строке).

только вот не хочет у меня теперь ПХП декодировать его))
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

ANDLL
Великий гастроном
Великий гастроном
Аватара пользователя
 
Сообщения: 3450
Зарегистрирован: 29.06.2003 (Вс) 18:55

Re: Base64 (как получить приемлимую скорость)

Сообщение ANDLL » 26.10.2009 (Пн) 14:03

Значит не так кодируешь
Гастрономия - наука о пище, о ее приготовлении, употреблении, переварении и испражнении.
Блог

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 14:09

ANDLL писал(а):Значит не так кодируешь

Штирлиц говорит что это валидный BASE64)))

видимо в шапке трабла :)
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Re: Base64 (как получить приемлимую скорость)

Сообщение iGrok » 26.10.2009 (Пн) 14:23

SSecurity писал(а):Если строку перегнать в массив бауйтовый то размер массива у меня получается в 2 раза больше
т.е. "AAAA" = {65,0,65,0,65,0,65,0,0}, следовательно и работать надо с нечетными элемнтами.

Если ты в эту строку перед этим прочитал содержимое файла - то чётные "нули" у тебя совсем лишние.
Это из-за того, что VB хранит строки в юникоде.
Чтобы получить правильный массив, используй b = StrConv(str, vbFromUnicode).
Или лучше читай сразу в массив.
label:
cli
jmp label

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 14:40

iGrok писал(а):
SSecurity писал(а):Если строку перегнать в массив бауйтовый то размер массива у меня получается в 2 раза больше
т.е. "AAAA" = {65,0,65,0,65,0,65,0,0}, следовательно и работать надо с нечетными элемнтами.

Если ты в эту строку перед этим прочитал содержимое файла - то чётные "нули" у тебя совсем лишние.
Это из-за того, что VB хранит строки в юникоде.
Чтобы получить правильный массив, используй b = StrConv(str, vbFromUnicode).
Или лучше читай сразу в массив.

сделал пока с нуликами ... наверно с позиции ресурсов надо сразу в массив байтовый читать файлик, согласен
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Base64 (как получить приемлимую скорость)

Сообщение Хакер » 26.10.2009 (Пн) 14:46

Метод с нечётными байтами недопустим.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 14:53

Хакер писал(а):Метод с нечётными байтами недопустим.

Поясни пожалуйста почему, если конечно не сложно.
Я так понимаю если речь пойдет о китайском в котором бьольше чем 256 символов алфавит ... вот там получится еррор)
Правильно понимаю?
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Re: Base64 (как получить приемлимую скорость)

Сообщение iGrok » 26.10.2009 (Пн) 14:59

SSecurity писал(а):сделал пока с нуликами ...

В смысле? Ты файл с этими нуликами кодируешь и отправляешь?
Ну вот он у тебя и получается в два раза больше, чем должен быть.. И никем потом открываться не будет заодно, потому, что формат нарушен.
label:
cli
jmp label

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 15:05

))) вообщем я сделал мини-проксик и посмотрел чтошлет опера и что шлю я :)
Насколько я могу судить по данным бинариков сформированных на этапе отправки

мой изначальный Data содержит именно то что и должен содержать (идентичен опере), однако на сервер приходят совсем иные данные, что в принципе не может меня не вводить в заблуждение :)

В чем прикол то?
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 15:08

iGrok писал(а):
SSecurity писал(а):сделал пока с нуликами ...

В смысле? Ты файл с этими нуликами кодируешь и отправляешь?
Ну вот он у тебя и получается в два раза больше, чем должен быть.. И никем потом открываться не будет заодно, потому, что формат нарушен.


Легко, как и писал выше беру нечетные, и их обрабатываю :) в итоге получается без лишних ... и не китайская:)

Код: Выделить всё
Private Function Base64Encode(ByRef IncStr As String) As String
  Dim ArrByte() As Byte
  Dim ResByte() As Byte
  Dim B1 As Byte
  Dim B2 As Byte
  Dim B3 As Byte
  Dim R1 As Byte
  Dim R2 As Byte
  Dim R3 As Byte
  Dim R4 As Byte
  Dim DobSmb As Byte
  Dim I As Long
  Dim F As Long
  Dim T As Long
  Dim LineCount As Long
  Dim FL As Long
  Dim LineSep As String
  Dim D As Long
  LineSep = vbCrLf
  DobSmb = (3 - (Len(IncStr) Mod 3)) Mod 3
  IncStr = IncStr & String(DobSmb, 0)
  ReDim ArrByte(LenB(IncStr))
  CopyMemory ArrByte(0), ByVal StrPtr(IncStr), LenB(IncStr)
  'ArrByte = IncStr
  F = Len(IncStr) \ 3
  'по идее можно сразу расчитать сколько будет байт в результате
  '(исх.массив / 3 * 4 + (исх.массив / 3 * 4) / 72 * (1 или 2))*2
  LineCount = F \ 18
  FL = UBound(ArrByte) / 3 * 4 + LineCount * LenB(LineSep)
  ReDim ResByte(FL)
  For I = 1 To LineCount
    CopyMemory ResByte(I * (72 + Len(LineSep)) * 2 - LenB(LineSep)), ByVal StrPtr(LineSep), LenB(LineSep)
  Next I
 
  'IncStr = IncStr & String(DobSmb, 0)
  For I = 1 To UBound(ArrByte) Step 6
    D = I \ 108
   
    B1 = ArrByte(I - 1)
    B2 = ArrByte(I + 1)
    B3 = ArrByte(I + 3)
    R1 = B1 \ 4
    R2 = (B1 Mod 4) * 16 + B2 \ 16
    R3 = (B2 Mod 16) * 4 + B3 \ 64
    R4 = B3 Mod 64
    T = ((I - 1) \ 6) * 8 + D * LenB(LineSep)
    ResByte(T) = ARR(R1)
    ResByte(T + 2) = ARR(R2)
    ResByte(T + 4) = ARR(R3)
    ResByte(T + 6) = ARR(R4)
  Next I

  Select Case DobSmb
    Case 1:
      ResByte(T + 4) = ARR(R3)
      ResByte(T + 6) = 61
    Case 2:
      ResByte(T + 4) = 61
      ResByte(T + 6) = 61
  End Select
  Base64Encode = ResByte
End Function


полкода можно убрать если корректно избавится от Юникода :)
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 16:12

Ура, мой бинарный файлик запостился на мой сервер :) ПХП сказал ОК, и принял данные:)
Проблема была в кодировке, для формирования теля запроса я использовала Стринг, он конечно был правильный, но отправлялся не так как надо. Я взял объявил массив и в последствии перевел сформированную строку к байтовому массиву, который и послал.

Код: Выделить всё
Function SendPostWHTTP(ByVal URL As String, ByVal fldName As String, ByVal FilePath As String, SubData As Dictionary, Optional ByVal locTimeOut As Integer = 60) As String
  Dim MyBoundary As String
  Dim data As String
  Dim TT() As Byte
  MyBoundary = GenerateBoundary
  data = GetFilePack(fldName, FilePath, MyBoundary)
  For Each xValue In SubData
    data = data & GetFormData(xValue, SubData(xValue), MyBoundary)
  Next
  data = data & "--" & MyBoundary & "--" & vbCrLf
  Set WR = New WinHttpRequest
  WR.Open "POST", URL, False
  WR.SetRequestHeader "User-Agent", "Opera/9.64 (Windows NT 5.1; U; ru) Presto/2.1.1"
  WR.SetRequestHeader "Accept", "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1"
  WR.SetRequestHeader "Accept-Language", "ru-RU,ru;q=0.9,en;q=0.8"
  WR.SetRequestHeader "Accept-Charset", "utf-8"
  WR.SetRequestHeader "Accept-Encoding", "deflate, gzip, x-gzip, identity, *;q=0"
  WR.SetRequestHeader "Connection", "Keep-Alive, TE"
  WR.SetRequestHeader "TE", "deflate, gzip, chunked, identity, trailers"
  WR.SetRequestHeader "Content-Type", "multipart/form-data; boundary=" & MyBoundary '& ";"
  TT = StrConv(data, vbFromUnicode)
  WR.SetRequestHeader "Content-Length", Str(Len(data))
  WR.Send TT
  WR.WaitForResponse locTimeOut
  If WR.Status = 200 Then SendPostWHTTP = WR.ResponseText
End Function
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Base64 (как получить приемлимую скорость)

Сообщение Хакер » 26.10.2009 (Пн) 20:11

SSecurity писал(а):
Хакер писал(а):Метод с нечётными байтами недопустим.

Поясни пожалуйста почему, если конечно не сложно.
Я так понимаю если речь пойдет о китайском в котором бьольше чем 256 символов алфавит ... вот там получится еррор)
Правильно понимаю?

Нет, неправильно. Ты имеешь дело с юникодом, и ты не имеешь никакого права работать с UCS-2-строчкой, как с ANSI, перемешанной от нечего делать с нулевыми байтами.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 20:18

Хакер писал(а):
SSecurity писал(а):
Хакер писал(а):Метод с нечётными байтами недопустим.

Поясни пожалуйста почему, если конечно не сложно.
Я так понимаю если речь пойдет о китайском в котором бьольше чем 256 символов алфавит ... вот там получится еррор)
Правильно понимаю?

Нет, неправильно. Ты имеешь дело с юникодом, и ты не имеешь никакого права работать с UCS-2-строчкой, как с ANSI, перемешанной от нечего делать с нулевыми байтами.

И что в этом случае делать? Ведь
{65,0,65,0,65,0,65,0} в BASE64 и {65,65,65,65} в BASE64 две совершенно разные вещи,
видимо просто StrConv надо ку строке применить и работать как ни в чем не бывало:)
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Base64 (как получить приемлимую скорость)

Сообщение Хакер » 26.10.2009 (Пн) 20:23

{65,0,65,0,65,0,65,0} в BASE64 и {65,65,65,65} в BASE64 две совершенно разные вещи,

Совершенно верно. Это разные вещи и в Base64, и без Base64.

Точно так же 24, и 77 --- разные вещи. Вопрос другой: что это за вещи?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Re: Base64 (как получить приемлимую скорость)

Сообщение iGrok » 26.10.2009 (Пн) 20:25

SSecurity писал(а):...видимо просто StrConv надо ку строке применить и работать как ни в чем не бывало:)

Нет. Это, в общем-то, тоже не совсем правильно. Если там откуда-то окажутся полноценные unicode-символы после "vbFromUnicode" ты их потеряешь.
Надо сразу читать в массив байт, и не париться со строками.

2Хакер:
Я не совсем помню.. Вся эта морока с юникодом ведь только из-за того, что VB хранит работает только с юникодными строками? То есть при чтении GET'ом из файла в строку, просто читается массив байт, и запихивается в юникодную строку? То есть по идее "полноценного" двухбайтного юникода там не может оказаться, пока его туда кто-нибудь специально или, что хуже, случайно не положит, так?
label:
cli
jmp label

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 20:38

iGrok писал(а):
SSecurity писал(а):...видимо просто StrConv надо ку строке применить и работать как ни в чем не бывало:)

Нет. Это, в общем-то, тоже не совсем правильно. Если там откуда-то окажутся полноценные unicode-символы после "vbFromUnicode" ты их потеряешь.
Надо сразу читать в массив байт, и не париться со строками.


Ну если делать универсальную систему - то нельзя а если известно какова будет область применения (и что значения 100% будут из кодировки Win-1251).
Ну а в противном случае Base64 получится X/3*8 т.е. в 2.66 раз больше чем исходный, в этом случае будет под всех :)
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Base64 (как получить приемлимую скорость)

Сообщение Хакер » 26.10.2009 (Пн) 20:40

А теперь скажи, если ты передаёшь текст идущий в кодировке Windows-1251, зачем его кодировать в Base64?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

SSecurity
Служба безопасности
Аватара пользователя
 
Сообщения: 1283
Зарегистрирован: 19.08.2003 (Вт) 1:11
Откуда: Россия, Мурманск

Re: Base64 (как получить приемлимую скорость)

Сообщение SSecurity » 26.10.2009 (Пн) 20:53

Хакер писал(а):А теперь скажи, если ты передаёшь текст идущий в кодировке Windows-1251, зачем его кодировать в Base64?

Хакер, твоими бы устами да ... :) Вопрос тут вопрос разделился на два
1. Base64 (соответсвует теме)
2. передача данных POST\GET-запросом через WinHTTPRequest. Пару часов назад мне всеже удалось победить передачу, там кодировать не нужно, но сам запрос идет в ЮТФ-8, данные которые он содержит (это данные в пределах Windows-1251), так что кодирование - здесь медленно отпадает на второй план.
Программист - это маленький Бог, а все его ошибки - это самостоятельные творения:)
Так задумано:)


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: AhrefsBot и гости: 95

    TopList