Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - Общий форум

Страница: 1 | 2 |

 

  Вопрос: Нужен совет по быстрому чтению файла Добавлено: 07.10.06 19:39  

Автор вопроса:  Neco | Web-сайт: neco.pisem.net | ICQ: 247906854 
В общем есть такой формат записи станционного протокола, в котором номера телефонов (и не только) записаны в hex-формате. Т.е. например есть телефон 555-12-34 - и в этом протоколе (если просматривать через hex-editor) я прямо эти цифры и вижу: 07 00 00 00 00 05 55 12 24, где 07 это количество знаков, которые надо отсчитать справа налево, чтобы получить номер телефона.
У меня уже есть способ чтения, но он тупой и я бы хотел попросить совета - как можно наиболее быстро прочитать hex в char?
вот кусок конвертора, которым пользовались в нашей конторке испокон веков, но по-моему и он далёк от совершенства:

  for (aa = 0, i = 0; aa < bytes; aa++)
  {
   tmp = in_buf[aa];
   hi  = (tmp >> 4) & 0x0F;
   lo  = tmp & 0x0F;
   out_buf[i++] = hex[hi];
   out_buf[i++] = hex[lo];
  }

где hex - массив: char hex[] = "0123456789ABCDEF";

Ответить

  Ответы Всего ответов: 22  

Номер ответа: 1
Автор ответа:
 BUG(O)R



ICQ: 827887 

Вопросов: 13
Ответов: 142
 Web-сайт: hunger.ru
 Профиль | | #1
Добавлено: 07.10.06 20:19
Почему тупой? Я в своих программах на ассемблере использую именно такой, правда реализован он иначе, побыстрее твоего будет, но сам алгоритм по-моему самый подходящий.
Хочешь быстрее - используй ассемблерную вставку.
Кстати, всё-таки можно сделать не через массив hex, а просто прибавлять 48 после сдвига, т.е. к переменным hi и lo, будет побыстрее.

Ответить

Номер ответа: 2
Автор ответа:
 -АлександР-



Вопросов: 55
Ответов: 1008
 Web-сайт: sham.clan.su
 Профиль | | #2
Добавлено: 07.10.06 21:36
for (aa = 0, i = 0; aa < bytes; aa++)
  {
   tmp = in_buf[aa];
   hi = (tmp >> 4) & 0x0F;
   lo = tmp & 0x0F;
   out_buf[i++] = hex[hi];
   out_buf[i++] = hex[lo];
  }
Что-то я не совсем улвавливаю его смысл.
Что такое tmp >> 4?
Может я плохо соображаю отого, что С плохо знаю. BuGOR-то - сразу понял в чем дело. . На VB ,быстрее м/б понял бы.

Насколько я догадался - out_buf - это массив char. Так зачем два раза ему присваивать значения шестнацатиричного кода?
Тпрррр....
Стоп! Вообще не понял, где у тебя принимаемое значение шестнадцатиричного кода или символ?
aa - у тебя по циклу бегает, а что ты преобразуешь?

Ответить

Номер ответа: 3
Автор ответа:
 Neco



ICQ: 247906854 

Вопросов: 133
Ответов: 882
 Web-сайт: neco.pisem.net
 Профиль | | #3
Добавлено: 07.10.06 23:29
>>4 это сдвиг на четыре бита. на vb.net это тоже есть.
присваивается один раз каждому следующему элементу - о чём говорит ++.
в массиве char - по индексам соот-щие aсsii значения.

В общем развил тему и составил массив из уже готовых значений для каждого значения байта:
    Dim bldr As New System.Text.StringBuilder(1000)
    Dim arr_hex() As Char = "0123456789ABCDEF".ToCharArray
    Dim arr_full_hex() As String = {"00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F","10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F","20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F","30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F","40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F","50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F","60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F","70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F","80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F","90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F","A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF","B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF","C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",";D0",";D1",";D2",";D3",";D4",";D5",";D6",";D7",";D8",";D9",";DA",";DB",";DC",";DD",";DE",";DF","E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF","F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"}

    Public Function ReadCharsToStr(ByVal cBytes As Integer) As String
        Try
            Dim c As Integer
            bldr.Length = 0
            Do While c < cBytes
                PrepareBuf()
                bldr.Append(arr_full_hex(buf(m_seek)))
                c += 1
                m_seek += 1
            Loop
            Return bldr.ToString
        Catch ex As Exception
            Throw ex
        End Try
    End Function

получилось довольно резво - 60 метровый файл разбирается менее чем за пять секунд.
У кого-нить есть ещё радикально новые мысли? Тут слишком быстро не бывает.

Ответить

Номер ответа: 4
Автор ответа:
 Neco



ICQ: 247906854 

Вопросов: 133
Ответов: 882
 Web-сайт: neco.pisem.net
 Профиль | | #4
Добавлено: 07.10.06 23:32
надо же - как испоганил страницу... :)

Ответить

Номер ответа: 5
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #5
Добавлено: 08.10.06 02:04
На ASM помнится я использовал команду XLAT. Принцип работы тот же самый.

Что -то вроде.

table db '0123456789ABCDEF'


mov al, 0Ah  ; в AL значение для преобразоваия
mov bx, offset table ; адрес таблицы
xlat ; упс ... готово в AL 41h  или 'А'


В общем команда xlat заменяет символ, на представленный в таблице. Удобна также для шифрования.

Ответить

Номер ответа: 6
Автор ответа:
 BUG(O)R



ICQ: 827887 

Вопросов: 13
Ответов: 142
 Web-сайт: hunger.ru
 Профиль | | #6
Добавлено: 08.10.06 09:33
В общем, написал я функцию, протестировал на файле размером 10 метров, на моём Duron950/256, обрабатываетcz меньше, чем за 100 миллисекунд.

Собственно, если ты пишешь на С/С++, то перекласть эту функцию как ассемблерную вставку труда не составит, если же на .NET, то быстрее, чем ты предложил сделать вряд ли удасться.


;ByteArray - указатель на массив байт, который
;требуется перевести в строку.
;OutBuffer - указатель на выходной строковый буфер
;len - размер ByteArray
b2a proc ByteArray:DWORD, OutBuffer:DWORD, len:DWORD
test len,1 ; Проверка чётности
je @f
inc len ; Длина есть число нечётное.
@@:
shr len,1 ; Делим на два. Результат - кол-во
mov ecx,len ; иттераций нашего цикла.
mov esi,ByteArray
mov edi,OutBuffer
@@:
lodsb        ; Грузим первый байт(например 12) в регистр al
shl ax,4     ; Сдвигаем и получаем в ax 0120
shr al,4     ; Сдвигаем ещё раз и получаем 0102
add ax,3030h ; Прибавляем коэффицент, после чего в ax имеем 3132
                         ;или "12" в acsii представлении
ror ax,8     ;Чтобы записать данные в правильном порядке нужно поменять значения младших регистров местами, т.е. имеем 3231
stosb        ;Записываем первый байт
shr ax,8     ;Подготавливаем к записи второй
stosb        ;Записываем его.
dec ecx
jne @b
ret
b2a endp

Ответить

Номер ответа: 7
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #7
Добавлено: 08.10.06 11:26
BUG(O)R
А зачем так -то, с кучей побитовых операций? Почему обычной подстановкой не сделать?
Мне думается будет быстрее?

Ответить

Номер ответа: 8
Автор ответа:
 BUG(O)R



ICQ: 827887 

Вопросов: 13
Ответов: 142
 Web-сайт: hunger.ru
 Профиль | | #8
Добавлено: 08.10.06 12:22
vito
Дело в том, что побитовые операции, а тем когда они производятся над регисрами выполняются очень быстро, единственное вместо вот этого:

stosb
shr ax,8
stosb

можно поставить:

mov word ptr[edi],ax
add edi,2

но при этом после lodsb придётся поставить:
xor ah,ah

И мы действительно получим небольшой прирост, порядка 15%, т.е. главный цикл будет так выглядеть:

@@:
lodsb
xor ah,ah
shl ax,4
shr al,4
add ax,3030h
ror ax,8
mov word ptr[edi],ax
add edi,2
dec ecx
jne @b



А о какой подстановке ты говоришь?

Ответить

Номер ответа: 9
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #9
Добавлено: 08.10.06 12:33
BUG(O)R
 В моем 5 посте.
Там всего 3 операции.
1. Пощение символа в регистр AL
2. Указатель на таблицу замены.
3. xlat

Итого вего 3 операции. B AL уже нужный нам символ.

Ответить

Номер ответа: 10
Автор ответа:
 BUG(O)R



ICQ: 827887 

Вопросов: 13
Ответов: 142
 Web-сайт: hunger.ru
 Профиль | | #10
Добавлено: 08.10.06 12:53
vito
А ты доведи до ума его, далее сравним, хотя я даже щас могу сказать, что в конечном варианте он у тебя будет медленнее моего имхо, т.к. тебе минимум за одну иттерацию придётся обратиться 3 раза к памяти(два раза чтение: загрузка байта, и загрузка табличного значения и одна операция записи, т.е. запись результата), а в данном случае обращения к памяти являются ключевым "тормозом".

Ответить

Номер ответа: 11
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #11
Добавлено: 08.10.06 23:17
BUG(O)R

Ничья! Победила дружба.:)
На сопоставимом железе примерно за те же 100 милисекунд 10 метровый файл. И где -то за 500 миллисекунд 50 метровый.

#include "stdafx.h"
#include "Windows.h"
#include <fstream>
#include <stdio.h>
char *hex = "0123456789ABCDEF";
using namespace std;

int _tmain(int argc, _TCHAR* argv[];)
{


char *t;
ifstream inputFile( "Turtlerock.avi", ios::in | ios::binary  ;);
if ( inputFile.fail())
return false;

inputFile.seekg( 0, ios::end );
long fileSize = inputFile.tellg();
inputFile.seekg( 0, ios::beg );

char *pBuffer = new char[fileSize];
inputFile.read((char*) pBuffer, fileSize );
inputFile.close();

// считали файл
const char *pPtr = pBuffer;



for (int i=0; i< fileSize; i++)
{

__asm
{
mov eax,pPtr
mov ebx,hex
xlat
mov t,eax
}
pPtr += sizeof( char );
}

scanf(t);
return 0;
}

Использовался интеловский компилер. Подкрученный на полную катушку.

Ответить

Номер ответа: 12
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #12
Добавлено: 09.10.06 00:56
Ошибочка.:)

__asm
{
mov eax, dword ptr [pPtr]
movzx eax, byte ptr [eax]
mov ebx,hex
xlat
mov t,eax
}

Ответить

Номер ответа: 13
Автор ответа:
 HOOLIGAN



Вопросов: 0
Ответов: 1066
 Профиль | | #13 Добавлено: 09.10.06 22:44
Мда...
Дико извиняюсь, но если номер 555-12-34, то в hex это должно быть что-то типа 02 2B 0C 22, а не 05 55 12 24.
Если информация всё-таки записана в виде 05 55 12 24, то это не hex-форма. Скорее нечто из области двоично-десятичных представлений.

Строки для всех номеров имеют вид "07 00 00 00 00 05 55 12 24" ? После 07 обязательно будут незначащие нули? Длина строк - величина постоянная или нет?

Ответить

Номер ответа: 14
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #14
Добавлено: 09.10.06 22:55
HOOLIGAN

Я тоже ничего не понял. Но если нужно перевсти hex в char пожалуйста.:)

Ответить

Номер ответа: 15
Автор ответа:
 Neco



ICQ: 247906854 

Вопросов: 133
Ответов: 882
 Web-сайт: neco.pisem.net
 Профиль | | #15
Добавлено: 09.10.06 22:59
Дико извиняюсь, но если номер 555-12-34, то в hex это должно быть что-то типа 02 2B 0C 22, а не 05 55 12 24

Нет вот именно 05 55 12 24. Такова реальность.

Длина строк - величина постоянная или нет?

Постоянная - в примере я не соблюдал, просто понатыкал несколько пар нулей. На самом деле для абонента А отведено 9 байт (2 на кол-во цифр, 16 на номер) для абонента Б - 18 (2 на кол-во, 34 на номер). Ну и там не только такого типа значения, есть и обычные бинарные (только с изменённым порядком байт - в них даются размеры блоков и записей), есть и acsii (фамилии операторов) поэтому надо постоянно смотреть в доку и по ней всё делать.

это не hex-форма

ну я не знал как её ещё обозвать.

Ответить

Страница: 1 | 2 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам