Привет всем! Народ, как лучше считать файл в определенный буфер, чтобы потом его можно было представить в шестнадцатеричном виде?
Выяснить размер файла, выделить буфер и прочитать. Или можно mmap'нуть. Это как больше нравится, в данной ситуации абсолютно без разницы.
Я сделал через fread. Узнал размер файла, выделил буфер и вот так считывал файл... Код (Text): for(int i = 0; i < dwSize; i++) { fread(&Buff[i], sizeof(BYTE), 1, File); } Работает, но медленно. А если еще переводить в шестнадцатеричный режим и отображать этот hex-код, то получается крайне долго. Подскажите, пожалуйста, как можно ускорить работу???
rzx твой алгос можно ускорить примерно в 4 раза Если тебе нужно считать к примеру 102 байта - то нет смысла в цикле 102 раза считывать по байту. Можно 25 раз считать 4 байта и 1раз 2 байта (DWORD и WORD соответственно) ПРоще говоря, сперва считываешь двордами, а в конце считываешь вордом, байтом или и тем и другим в зависимости от остатка. printf, sprintf, wsprintf довольно медленные функции и если ты отображаешь каждый байт через них - то на больших объемах данных получится действительно крайне медлено. Напиши на асме свою функцию перевода числа в строку. А после уже всю строку выведи на экран.
rzx Само собой. Ведь вы читаете по одному байту. Почему-бы не прочитать все сразу? И еще, наверно стоит не забыть включить бинарный режим при открытии. А с длинными файлами лучше всего мапить.
Ну или по 4 байта - все равно 32-битная шина данных... ЗЫ. Насчет длинных файлов - вообще говоря, при размере > 1MB выделять память из heap-а не стоит, лучше - VirtualAlloc
Вот пример ф-ии, которая у меня когда-то давно открывала файл в hexDump-е. Там МАХ размер файла 2^32(4 Гб). Мапится ВСЕ)))) это неправильно, надо кусочками(просто я его за 15 мин написал и доделывать мне уже не надо было ). Код (Text): LRESULT HandleFileOpen( IN PHexDumpInfo pInfo, IN HWND hWnd) { OPENFILENAME ofn; ULONG dwFileSizeHigh; ZeroMemory(&ofn,sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(ofn); ofn.lpstrFilter = L"All(*.*)\0*.*\0Text(*.txt)\0*.txt\0C++ Files(*.c, *.cpp, *.h)\0*.c;*.cpp;*.h\0"; //Строка с шаблонами имен искомых файлов ofn.hwndOwner = hWnd; ofn.lpstrFile = pInfo->wszFileName; ofn.nMaxFile = sizeof(pInfo->wszFileName); ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if(GetOpenFileName(&ofn)) { pInfo->hFile = CreateFile( pInfo->wszFileName, GENERIC_READ, FILE_SHARE_READ,//0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (pInfo->hFile == INVALID_HANDLE_VALUE) { MessageBox(NULL,L"Ошибка при открытии файла!!!",L"Error",MB_OK); return 0; } pInfo->dwFileSize = GetFileSize( pInfo->hFile, &dwFileSizeHigh); if (dwFileSizeHigh > 0) { MessageBox(hWnd,L"Файл слишком большой!",L"Error!",0); CloseHandle(pInfo->hFile); pInfo->dwFileSize = 0; return 0; } pInfo->hMap = CreateFileMapping( pInfo->hFile, NULL, PAGE_READONLY, 0, pInfo->dwFileSize, NULL); if (pInfo->hMap == INVALID_HANDLE_VALUE || pInfo->hMap == 0) { MessageBox(NULL,L"Ошибка при открытии файла!!!",L"Error!",MB_OK); CloseHandle(pInfo->hFile); pInfo->dwFileSize = 0; return 0; } pInfo->fFileIsOpen = TRUE; pInfo->dwTotalStringAmount = pInfo->dwFileSize /16; if ( (pInfo->dwFileSize %16) > 0) { pInfo->dwTotalStringAmount++; } pInfo->pMappedBuffer = MapViewOfFile( pInfo->hMap, FILE_MAP_READ, 0, 0, pInfo->dwFileSize); if (pInfo->pMappedBuffer == NULL) // это указатель () на буффер (PVOID). чтобы его норм. вывести, надо сделать приведение к PBYTE и по i выводить { MessageBox(NULL,L"Ошибка при открытии файла!!!",L"Error!",MB_OK); CloseHandle(pInfo->hFile); CloseHandle(pInfo->hMap); pInfo->dwFileSize = 0; } SetWindowText(hWnd,pInfo->wszFileName); InvalidateRect(hWnd,NULL,TRUE); } return 0; } Будут вопросы - обращайтесь)
Какая шина данных?! Чтение с диска всегда происходит секторами, если уж на то пошло, но вообще чем меньше вызовов системных функций, тем лучше. Код Код (Text): for(int i = 0; i < dwSize; i++) { fread(&Buff[i], sizeof(BYTE), 1, File); } можно заменить на простой вызов Код (Text): fread(Buff, sizeof(BYTE), dwSize, File); Приколы с чтением по кусочкам нужны, если файл очень большой и неразумно грузить его в память сразу весь.
Вот делал аналог BIN2DB из масма, только для синтаксиса Делфи. Отображатся результаты должны в RichEdit, т.к. c простым Multiline Edit большые обьемы будут сильно тормозить. Код (Text): procedure RawDataToPasCode(RawData, OutputData: Pointer; DataSize: Cardinal); assembler; register; const HexTable: Array[0..255] of WORD = ( $3030, $3130, $3230, $3330, $3430, $3530, $3630, $3730, $3830, $3930, $4130, $4230, $4330, $4430, $4530, $4630, $3031, $3131, $3231, $3331, $3431, $3531, $3631, $3731, $3831, $3931, $4131, $4231, $4331, $4431, $4531, $4631, $3032, $3132, $3232, $3332, $3432, $3532, $3632, $3732, $3832, $3932, $4132, $4232, $4332, $4432, $4532, $4632, $3033, $3133, $3233, $3333, $3433, $3533, $3633, $3733, $3833, $3933, $4133, $4233, $4333, $4433, $4533, $4633, $3034, $3134, $3234, $3334, $3434, $3534, $3634, $3734, $3834, $3934, $4134, $4234, $4334, $4434, $4534, $4634, $3035, $3135, $3235, $3335, $3435, $3535, $3635, $3735, $3835, $3935, $4135, $4235, $4335, $4435, $4535, $4635, $3036, $3136, $3236, $3336, $3436, $3536, $3636, $3736, $3836, $3936, $4136, $4236, $4336, $4436, $4536, $4636, $3037, $3137, $3237, $3337, $3437, $3537, $3637, $3737, $3837, $3937, $4137, $4237, $4337, $4437, $4537, $4637, $3038, $3138, $3238, $3338, $3438, $3538, $3638, $3738, $3838, $3938, $4138, $4238, $4338, $4438, $4538, $4638, $3039, $3139, $3239, $3339, $3439, $3539, $3639, $3739, $3839, $3939, $4139, $4239, $4339, $4439, $4539, $4639, $3041, $3141, $3241, $3341, $3441, $3541, $3641, $3741, $3841, $3941, $4141, $4241, $4341, $4441, $4541, $4641, $3042, $3142, $3242, $3342, $3442, $3542, $3642, $3742, $3842, $3942, $4142, $4242, $4342, $4442, $4542, $4642, $3043, $3143, $3243, $3343, $3443, $3543, $3643, $3743, $3843, $3943, $4143, $4243, $4343, $4443, $4543, $4643, $3044, $3144, $3244, $3344, $3444, $3544, $3644, $3744, $3844, $3944, $4144, $4244, $4344, $4444, $4544, $4644, $3045, $3145, $3245, $3345, $3445, $3545, $3645, $3745, $3845, $3945, $4145, $4245, $4345, $4445, $4545, $4645, $3046, $3146, $3246, $3346, $3446, $3546, $3646, $3746, $3846, $3946, $4146, $4246, $4346, $4446, $4546, $4646 ); asm PUSH EBX PUSH EDI PUSH ESI MOV EDI, EAX MOV EBX, OFFSET HexTable MOV ESI, 1 @loop: DEC ESI JNZ @1 MOV DWORD PTR [EDX], $20200A0D ADD EDX, 4 MOV DWORD PTR [EDX], $20202020 ADD EDX, 4 MOV ESI, 16 @1: XOR EAX, EAX MOV AL, BYTE PTR [EDI] SHL EAX, 1 ADD EAX, EBX MOV AX, WORD PTR [EAX] MOV WORD PTR [EDX + 1], AX MOV BYTE PTR [EDX], '$' MOV BYTE PTR [EDX + 3], ',' ADD EDX, 4 INC EDI DEC ECX JNZ @loop DEC EDX MOV DWORD PTR [EDX], $20200A0D ADD EDX, 4 MOV DWORD PTR [EDX], $3B292020 ADD EDX, 4 MOV DWORD PTR [EDX], $00000A0D POP ESI POP EDI POP EBX end; procedure Proceed; var i, j, k: Cardinal; hInputFile: HFILE; hMapFile: THandle; pViewFile: Pointer; OutputBuf: Cardinal; Buf: Array[0..39] of AnsiChar; procedure ErrExit(ErrIndex: Byte; ErrMsg: PAnsiChar); begin if ErrIndex = 0 then GlobalFree(OutputBuf); if ErrIndex in [0,4] then UnMapViewOfFile(pViewFile); if ErrIndex in [0,3,4] then CloseHandle(hMapFile); if ErrIndex in [0,2,3,4] then CloseHandle(hInputFile); SetDlgItemText(Handle, IDC_STATUSBAR, ErrMsg); if ErrIndex <> 0 then MessageBox(Handle, ErrMsg, 'Error', MB_OK OR MB_ICONERROR); end; begin hInputFile:=CreateFile(@FileName[0], GENERIC_READ, FILE_SHARE_READ OR FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if hInputFile = INVALID_HANDLE_VALUE then begin ErrExit(1, ' Can'#39't open input file.'); Exit; end; FileSize:=GetFileSize(hInputFile, @i); if FileSize = 0 then begin ErrExit(2, ' File is empty.'); Exit; end; if i <> 0 then begin ErrExit(2, ' File is too large.'); Exit; end; hMapFile:=CreateFileMapping(hInputFile, nil, PAGE_READONLY, 0, 0, nil); if hMapFile = INVALID_HANDLE_VALUE then begin ErrExit(2, ' Can'#39't create file mapping.'); Exit; end; pViewFile:=MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); if pViewFile = nil then begin ErrExit(3, ' Can'#39't view file mapping.'); Exit; end; OutputBuf:=GlobalAlloc(GMEM_FIXED, (FileSize shl 2) + (FileSize shr 1) + MAX_PATH + 50); if OutputBuf = 0 then begin ErrExit(4, ' Can'#39't get memory for processing.'); Exit; end; //============================================================================== DWORD(Pointer(OutputBuf )^):=$61442020; DWORD(Pointer(OutputBuf + 4)^):=$203A6174; DWORD(Pointer(OutputBuf + 8)^):=$61727241; DWORD(Pointer(OutputBuf + 12)^):=$2E305B79; Byte(Pointer(OutputBuf + 16)^):=$2E; i:=Dw2Str(FileSize - 1, Pointer(OutputBuf + 17)); DWORD(Pointer(OutputBuf + 17 + i)^):=$666F205D; DWORD(Pointer(OutputBuf + 21 + i)^):=$74794220; DWORD(Pointer(OutputBuf + 25 + i)^):=$203D2065; j:=strlen(@FileName[0]); k:=j; while (j > 0) AND (FileName[j] <> '\') do dec(j); if j > 5 then begin DWORD(Pointer(OutputBuf + 29 + i)^):=$20202F2F; _CopyMemory(@FileName[j + 1], Pointer(OutputBuf + 32 + i), k - j); inc(i, k - j + 2); end; DWORD(Pointer(OutputBuf + 29 + i)^):=$20200A0D; DWORD(Pointer(OutputBuf + 33 + i)^):=$20282020; SetWindowText(Handle, @FileName[0]); //////// RawDataToPasCode(pViewFile, Pointer(OutputBuf + i + 36), FileSize); //////// SetDlgItemText(Handle, IDC_OUTPUT, Pointer(OutputBuf)); Buf[0]:=' '; i:=Dw2Str(FileSize, @Buf[1]); DWORD(Pointer(@Buf[i + 1])^):=$74796220; DWORD(Pointer(@Buf[i + 5])^):=$6C207365; DWORD(Pointer(@Buf[i + 9])^):=$6564616F; DWORD(Pointer(@Buf[i + 13])^):=$6E692064; DWORD(Pointer(@Buf[i + 17])^):=$69646520; DWORD(Pointer(@Buf[i + 21])^):=$00726F74; ErrExit(0, @Buf[0]); end;
Есть еще такой СИшный исходнег from Veacheslav Patkov Код (Text): /* * binary to xxx converter * * Copyright (c) 2007-2008, Veacheslav Patkov. * aLL rights reserved. * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #define BIN2XXX_VERSION "0.06" char erropt[5],oname[256],ident[256] = "ident"; void error(char *format, ...) { va_list ap; fprintf(stderr,"bin2xxx: error: "); va_start(ap,format); vfprintf(stderr,format,ap); va_end(ap); fprintf(stderr,"\n"); exit(1); } int incomp_opt(int opt) { static int i = 0; if (opt && !strchr(erropt,opt)) erropt[i++] = opt; return i; } int main(int argc, char **argv) { int c; unsigned char format = 0, op_cmt = 0, op_dec = 0, op_esch = 0; unsigned char op_esco = 0, op_esco3 = 0; unsigned int align = 10, i, offset, start = 0; unsigned int end = (unsigned int)-1, size = end; FILE *fi, *fo; if (argc == 1) { printf("bin2xxx - binary to xxx converter version " BIN2XXX_VERSION "\n" "usage: bin2xxx <format> [options] [file]\n" "formats:\n" " c c/c++\n" " n nasm/yasm\n" " m masm/tasm/fasm\n" " g gnu assembler\n" " p pascal\n" " a ascii text\n" "options:\n" " -c comment current file offset at each line\n" " -d write bytes as decimal number, default: hexademical\n" " -a <align> align to <align>, default: 10\n" " -i <ident> identifier is <ident>, default: `ident'\n" " -r <n[-m]> convert bytes from file offset <n> [to <m>] (hex)\n" " -o <file> save output to <file>, default: stdout\n" " -h c: write bytes as hex esc-codes in string\n" " -t c: write bytes as oct esc-codes in string\n" " -T c: write bytes as oct esc-codes in string (3 digit)\n" "example:\n" " bin2xxx c -r 2e0-3ff -cd -a 16 -i sample -o oname.h iname.exe\n"); return 0; } argv++; argc--; if (strlen(*argv) != 1 || ((format = **argv) != 'c' && format != 'n' && format != 'm' && format != 'g' && format != 'p' && format != 'a')) error("unrecognized format: %s",*argv); parse_opt: while (--argc > 0 && **++argv == '-') while ((c = *++*argv) != 0) switch (c) { case 'c': op_cmt = 1; break; case 'd': op_dec = 1; incomp_opt(c); break; case 'h': op_esch = 1; incomp_opt(c); break; case 't': op_esco = 1; incomp_opt(c); break; case 'T': op_esco3 = 1; incomp_opt(c); break; case 'a': case 'i': case 'r': case 'o': argc--; if (!argc) error("no argument for `-%c' option",c); argv++; switch (c) { case 'a': align = (unsigned int)strtoul(*argv,0,10); if (align < 1 || align > 100) error("incorrect argument for `-%c' option: %s",c,*argv); goto parse_opt; case 'i': strcpy(ident,*argv); goto parse_opt; case 'o': strcpy(oname,*argv); goto parse_opt; case 'r': if (sscanf(*argv,"%x-%x",&start,&end) != 2 && sscanf(*argv,"%x",&start) != 1) error("incorrect argument for `-%c' option: %s",c,*argv); goto parse_opt; } default: error("unrecognized option: -%c",c); } if (incomp_opt(0) >= 2) error("incompatible options: -%s",erropt); if (!argc) fi = stdin; else if (!(fi = fopen(*argv,"rb"))) error("cannot open file `%s'",*argv); if (!oname[0]) fo = stdout; else if (!(fo = fopen(oname,"wb"))) error("cannot open file `%s'",oname); if (fi != stdin) { fseek(fi,0,SEEK_END); size = ftell(fi) - 1; size = size > end ? end : size; fseek(fi,start,SEEK_SET); } else if (start) error("option `-r' is not allowed to stdin"); switch (format) { case 'c': if (op_esch || op_esco || op_esco3) fprintf(fo,"unsigned char %s[] =\n \"",ident); else fprintf(fo,"unsigned char %s[] = {\n ",ident); break; case 'n': case 'm': fprintf(fo,"%s\tdb ",ident); break; case 'g': fprintf(fo,"%s:\t.byte ",ident); break; case 'p': fprintf(fo,"%s: array[0..%u] of byte = (\n ", ident, fi == stdin ? 0: size-start); case 'a': break; } for (i = 0, offset = start; (c = fgetc(fi)) != EOF && offset <= end; i++, offset++) { switch (format) { case 'c': if (!(i % align) && i) { if (op_esch || op_esco || op_esco3) { if (op_cmt) fprintf(fo,"\" /* 0x%08x */\n \"",offset-align); else fprintf(fo,"\"\n \""); } else { if (op_cmt) fprintf(fo," /* 0x%08x */\n ",offset-align); else fprintf(fo,"\n "); } } if (op_esch) fprintf(fo,"\\x%02x",c); else if (op_esco) fprintf(fo,"\\%o",c); else if (op_esco3) fprintf(fo,"\\%03o",c); else if (op_dec) fprintf(fo,"%3u",c); else fprintf(fo,"0x%02x",c); if (offset != size && !op_esch && !op_esco && !op_esco3) fprintf(fo,","); break; case 'n': if (!(i % align) && i) { if (op_cmt) fprintf(fo," ; 0x%08x\n\tdb ",offset-align); else fprintf(fo,"\n\tdb "); } if (op_dec) fprintf(fo,"%3u",c); else fprintf(fo,"0x%02x",c); if (((i+1) % align) && offset != size) fprintf(fo,","); break; case 'm': if (!(i % align) && i) { if (op_cmt) fprintf(fo," ; 0x%08x\n\tdb ",offset-align); else fprintf(fo,"\n\tdb "); } if (op_dec) fprintf(fo,"%3u",c); else fprintf(fo,"%03xh",c); if (((i+1) % align) && offset != size) fprintf(fo,","); break; case 'g': if (!(i % align) && i) { if (op_cmt) fprintf(fo," /* 0x%08x */\n\t.byte ",offset-align); else fprintf(fo,"\n\t.byte "); } if (op_dec) fprintf(fo,"%3u",c); else fprintf(fo,"0x%02x",c); if (((i+1) % align) && offset != size) fprintf(fo,","); break; case 'p': if (!(i % align) && i) { if (op_cmt) fprintf(fo," { 0x%08x }\n ",offset-align); else fprintf(fo,"\n "); } if (op_dec) fprintf(fo,"%3u",c); else fprintf(fo,"$%02x",c); if (offset != size) fprintf(fo,","); break; case 'a': if (!(i % align) && i) { if (op_cmt) fprintf(fo," ; 0x%08x\n",offset-align); else fprintf(fo,"\n"); } if (op_dec) fprintf(fo,"%3u",c); else fprintf(fo,"%02x",c); if (offset != size) fprintf(fo," "); break; } } switch (format) { case 'c': if (op_esch || op_esco || op_esco3) fprintf(fo,"\";\n"); else fprintf(fo,"\n};\n"); break; case 'n': case 'm': case 'g': fprintf(fo,"\n"); break; case 'p': fprintf(fo,"\n);\n"); case 'a': break; } fclose(fi); fclose(fo); return 0; } Но меня что-то берут сомнения в его эффективности...
diamond Какая шина данных?! Чтение с диска всегда происходит секторами Да уж, ступил, sorry... Видимо, надо было уже ложиться спать
_basmp_ А с реально длинными (3+ гига) файлами пожалуй лучше не мапить. diamond Накопители в последнее время становятся всё более разными. Не уверен, что на флэш-драйвах физически существуют сектора. Даже так: уверен, что НЕ существуют.
CyberManiac По моим сведениям, хотя физически на флэшках секторов и нет, но в программном интерфейсе всё равно чтение/запись осуществляется целыми секторами (512 байт). Поправьте, если заблуждаюсь.
Какая разница - есть сектора, нет секторов Главное, что скорость чтения\записи как HDD, так и USB флэшек оставляет желать лучшего. Поэтому ОС с девайса ес-но по одному символу не читает, а юзает упреждающее чтение данных в режиме ДМА в системный кэш большими блоками (в винде до 64К). Поэтому при чтении данных малыми порциями время в основном тратится на сами вызовы ReadFile и поэтому ес-но лучше за раз читать побольше и пореже (для уменьшения накладных расходов на ReadFile достаточно юзать буфер размером до 4-8К) PS: В сишном стриме вроде как есть собственный буфер чтения\записи, размер которого можно изменить через setbuf\setvbuf