Комп'ютерні науки > Ідея буферизації
Зрозуміло, що коли обробляється файл записів фіксованого розміру, то цей розмір можна задавати і для блока. Наприклад, записи типу Student=record Sname, Name : string[20]; Ball : real end мають розмір 21+21+6=48 (байтів). Саме це значення повертається з виклику функції SizeOf(Student). І взагалі, з виклику вигляду SizeOf(ім’ я-типу) повертається кількість байтів, що займаються значеннями цього типу, наприклад, SizeOf(char)=1, SizeOf(integer)=2 тощо. Отже, файл f записів типу Student можна відкрити викликом ReSet(f, SizeOf(Student)). Після цього виклик вигляду BlockRead(f, Buf, n, nreal) задає читання n блоків по 48 байтів у пам’ ять змінної Buf. Головну роль у швидкості читання безтипових файлів відіграє розмір "внутрішнього буфера". Чим він більше, тим менше звернень до зовнішнього носія і швидше обробка файла. Але все добре в міру. Можете перевірити твердження, що за розмірів буфера, кратних 512 байтам і більших 8K байтів, швидкість читання файлів практично стала. Процедура блочного виведення BLOCKWRITE також має 4 аналогічні параметри. Відмінність її в тім, що дані з "внутрішнього буфера" через блок записуються в кінець файла. Зрозуміло, спочатку для файла треба установити розмір "зовнішнього" буфера викликом вигляду ReWrite(f, m). Повернемося до задачі копіювання й напишемо програму, виконання якої в сотні (!) разів швидше від програми StupidCopy. У ролі "внутрішнього буфера" виступає масив символів Buf розміром у Bufsz=32K байтів. Спочатку за викликом FileSize визначається розмір вхідного файла в байтах, а потім файл читається в масив порціями по Bufsz байтів. Обробка цього буфера в даному разі полягає в блочному копіюванні у вихідний файл. Остання порція може містити менше, ніж Bufsz байтів – масив заповнюється та переписується в файл не до кінця. program QuickCop; const Bufsz=32768; var f, g : file; Buf : array[1..Bufsz] of char; restfil, portion : Longint; rdin, wrou : word; s : string; begin writeln( 'Задайте ім'я файла-джерела:'); readln (s); assign (f , s ); writeln( 'Задайте ім'я цільового файла:'); readln (s); assign (g , s ); reset(f, 1); rewrite(g, 1); restfil:=filesize(f); while restfil>0 do begin if restfil>Bufsz then portion:=Bufsz else portion:=restfil; dec(restfil, portion); Blockread (f, Buf, portion, rdin); if rdin<>portion then begin writeln('Помилка читання файла'); halt end; Blockwrite(g, Buf, portion, wrou); if wrou<>portion then begin writeln('Помилка запису файла'); halt end; end; close(g); close(f); end. Два зауваження щодо цієї програми. По-перше, до неї можна додати обчислення часу, який займає обробка файла. Для цього слід задати на початку програми підключення модуля Dos і скористатися його процедурою GETTIME. Слід означити 4 змінні типу Word, наприклад, th, tm, ts, tms : word. Можна записати виклик Gettime(th, tm, ts, tms) десь на початку тіла програми, наприклад, перед відкриванням файлів. За його виконання змінним присвоюються відповідно години, хвилини, секунди ті мілісекунди від вбудованого в комп’ ютер годинника. Обробка значень цих змінних залежить від смаків програміста. Наприклад, за ними можна обчислити час у сотих долях секунди. Означимо змінну tim типу longint: tim:=((th*60+tm)*60+ts)*100+tms div 10; Наприкінці програми запишемо gettime(th, tm, ts, tms); tim:=((th*60 + tm)*60 + ts)*100 + tms div 10 - tim; writeln('Витрачено часу : ', (tim div 100):1, '.', (tim mod 100 div 10):1, (tim mod 100 mod 10):1, ' sec' ) Тоді друкується час виконання у секундах на зразок 3.62 чи 0.01. Друге зауваження стосується способу задання імен файлів при виконанні програми. Змушувати користувача набирати їх щоразу на клавіатурі – не найкращий варіант. Система Турбо Паскаль дозволяє задавати імена файлів у командному рядку виклику програми і читати їх звідси за допомогою функції PARAMSTR. Наприклад, якщо виклик програми QuickCop записати у вигляді QuickCop file.in file.out то рядок 'file.in' є значенням, що повертається з виклику ParamStr(1), 'file.out' – ParamStr(2). У такому разі зв’ язування файлів можна задати так: assign(f, ParamStr(1)); assign(g, ParamStr(2)). І взагалі, нехай словом вважається послідовність символів, відмінних від пропуска. Слова після назви програми в командному рядку є рядками, що повертаються з викликів ParamStr із відповідними номерами. Кількість слів повертається з виклику функції PARAMCOUNT (без аргументів). Отже, якщо користувач програми QuickCop не задав імена файлів у командному рядку, можна примусити його задати їх з клавіатури, написавши на початку програми щось на зразок: case ParamCount of 0: begin writeln('Задайте ім'я вхідного файла'); readln(s); assign(f, s); writeln('Задайте ім'я цільового файла'); readln(s); assign(g, s); end; 1: begin assign(f, ParamStr(1)); writeln('Задайте ім'я цільового файла'); readln(s); assign(g, s); end else begin assign(f, ParamStr(1)); assign(g, ParamStr(2)); end end.
Назва: Ідея буферизації Дата публікації: 2005-02-22 (667 прочитано) |