#include <stdio.h>
#define BUFSIZE (32)
int main(int argc, char **argv) {
char buf[BUFSIZE];
FILE *fi, *fo;
int errorlevel = 1;
size_t bytes_read;
if(argc < 3) {
printf("file copy. usage:\n%s infile outfile\n", argv[0]);
goto done;
}
if(!(fi = fopen(argv[1], "r"))) {
printf("cannot open input file: %s\n", argv[1]);
goto done;
}
if(!(fo = fopen(argv[2], "w+"))) {
printf("cannot open output file: %s\n", argv[2]);
goto closefi;
}
for(; ; ) {
bytes_read = fread(buf, 1, BUFSIZE, fi);
fwrite(buf, 1, bytes_read, fo);
if(bytes_read != BUFSIZE && feof(fi)) {
break;
}
}
fclose(fo);
closefi:
fclose(fi);
errorlevel = 0;
done:
return errorlevel;
}
Сколько байт читать (записывать) из файла за один раз?
Открываю файл на чтение/запись, но не знаю размер блока, который нужно считывать за 1 раз. Известно, что чтение маленькими блоками сильно замедляет программу, но не делать же их огромными. Возникает вопрос, какой самый оптимальный вариант и в каких случаях?
самый оптимальный - это тот, который нужен для решения твоей задачи - можешь, конечно читать весь файл за раз, а потом работать с буфером в оперативе - это в теории должно быть быстрее, но не факт, при этом, что файл не будет слишком большим чтобы не использовать свап, тогда наоборот - нужно читать этот файл порциями - ведь обращением к свапу ничуть не быстрее, чем обращение к обычному файлу, учитывая, что свап по сути то и есть обычный файл... ну и так далее :)
Для загрузки текстовых файлов в Delphi и Builder'е можно использовать TStringList->LoadFile без всяких буферов и открытыя/закрытия файла.
А вообще, оптимальное соотношение чтения/хранения зависит от текущих условий работы алгоритма
наиболее оптимальный размер это 8192 байт = 8 КБ
Это почему?
- Петька, приборы?!
- 567!
- Петька, что "567"?!
- А что "приборы", Василий Иванович?
Оптимальный - равный размеру кластера диска или кратный ему. 8к обычно туда попадает. На самом деле пофиг - лишнее все равно закешируется системой.
А вообще, оптимальное соотношение чтения/хранения зависит от текущих условий работы алгоритма[/QUOTE]
В принципе для меня не так важно в какой среде. Приходилось писать и на VB, и на Delphi, и на Паскале. Файл открывался как текстовый. Размер файла измерялся мегабайтами. И здесь волновало только какой размер блока использовать. Теперь суть для мнея ясна.
Дык в зависимости от того что ты делаешь с этим файлом после загрузки. Если редактируешь фотографию, то возможно придется целиком загружать. Если перекодируешь кои8 в Утф8 то в зависимости от платформы после какого-то значения размер окна уже не влияет на производительность. Где-то я находил подобный бенчмарк, да его и самому сделать нетрудно...
Если посмотрите исходники класса TParser в Дельфи, то там читается блоками по 4 кб
Если мне файл надо скопировать, по сколько лучше читать? Или по сколько читать при перекодировании wav файла? Или лучше бенчмарк сделать и проверить всё на себе?
Можно использовать 4 Кб (4096).
Попробуй простой копировальщик. Меняй значение BUFSIZE
1) каждое обращение к винту его изнашивает. И, скажем, на рабочем компе такое приводит к износу быстро.
2) каждое обращение к винту - перемещение головок, время.
Что же касается тех нечастых случаев, когда решаеая задача не навязывает структурную единицу для чтения...
Приведенный выше листинг Svyatozar-а был несколько модифицирован.
Код:
#include <stdio.h>
#include <windows.h>
#define BUFSIZE (2)
int main(int argc, char **argv) {
bool APIOK = true;
long time1, time2;
HINSTANCE hModule=NULL;
typedef BOOL (_cdecl MESS)(UINT);
MESS* me=NULL;
hModule=::LoadLibrary(\"kernel32.dll\");
me=(MESS*)::GetProcAddress((HMODULE)hModule,\"GetTickCount\");
UINT type = 1;
if ( APIOK )
time1 = (*me)(type);
char buf[BUFSIZE];
FILE *fi, *fo;
int errorlevel = 1;
size_t bytes_read;
if(argc < 3) {
printf(\"file copy. usage:n%s infile outfile\\n\", argv[0]);
goto done;
}
if(!(fi = fopen(argv[1], \"r\"))) {
printf(\"cannot open input file: %s\\n\", argv[1]);
goto done;
}
if(!(fo = fopen(argv[2], \"w+))) {
printf(\"cannot open output file: %s\\n\", argv[2]);
goto closefi;
}
for(; ; ) {
bytes_read = fread(buf, 1, BUFSIZE, fi);
fwrite(buf, 1, bytes_read, fo);
if(bytes_read != BUFSIZE && feof(fi)) {
break;
}
}
fclose(fo);
closefi:
fclose(fi);
errorlevel = 0;
done:
time2 = (*me)(type);
printf (\"exec time: %d\\n\", time2 - time1);
return errorlevel;
}
#include <windows.h>
#define BUFSIZE (2)
int main(int argc, char **argv) {
bool APIOK = true;
long time1, time2;
HINSTANCE hModule=NULL;
typedef BOOL (_cdecl MESS)(UINT);
MESS* me=NULL;
hModule=::LoadLibrary(\"kernel32.dll\");
me=(MESS*)::GetProcAddress((HMODULE)hModule,\"GetTickCount\");
UINT type = 1;
if ( APIOK )
time1 = (*me)(type);
char buf[BUFSIZE];
FILE *fi, *fo;
int errorlevel = 1;
size_t bytes_read;
if(argc < 3) {
printf(\"file copy. usage:n%s infile outfile\\n\", argv[0]);
goto done;
}
if(!(fi = fopen(argv[1], \"r\"))) {
printf(\"cannot open input file: %s\\n\", argv[1]);
goto done;
}
if(!(fo = fopen(argv[2], \"w+))) {
printf(\"cannot open output file: %s\\n\", argv[2]);
goto closefi;
}
for(; ; ) {
bytes_read = fread(buf, 1, BUFSIZE, fi);
fwrite(buf, 1, bytes_read, fo);
if(bytes_read != BUFSIZE && feof(fi)) {
break;
}
}
fclose(fo);
closefi:
fclose(fi);
errorlevel = 0;
done:
time2 = (*me)(type);
printf (\"exec time: %d\\n\", time2 - time1);
return errorlevel;
}
Здесь в начале и в конце выполнения програмы вызывается функция API функция GetTickCount, которая возвращает время, прошедшее с момента старта системы в милисекундах. Затем в выводится их разность, т.е. время выполнения цикла копирования.
Вот результаты
(2.exe - скопилировано для BUFFSIZE = 2, 1024.exe для BUFFSIZE = 1024)
запуск 2.exe - exec time: 42515
запуск 2.exe - exec time: 29844
запуск 2.exe - exec time: 29188
запуск 2.exe - exec time: 38234
запуск 2.exe - exec time: 34141
запуск 2.exe - exec time: 36157
запуск 1024.exe - exec time: 22109
запуск 1024.exe - exec time: 50469
запуск 1024.exe - exec time: 57484
запуск 1024.exe - exec time: 61266
запуск 1024.exe - exec time: 62828
запуск 2.exe - exec time: 55672
запуск 2.exe - exec time: 27578
запуск 1024.exe - exec time: 30609
Файл ок. 200 мб. Таким образом, не вижу четкой зависиости между размером буфера, и временем обработки.
Читайте данные по столько байт, сколько нужно для обработки. Главное - чтобы размер буфера был под контролем и не достигал огромной величины (не содержал 200 Мб в оперативной памяти).
Не получится ли, что подстраивание под "наиболее быстрый" размер буфера чтения/записи будет ресурсов и времени тратить больше, чем вся эта чудо экономия?????
2) Нет не получится.
Весь смысл в буферизации как раз и состоит в том, чтобы увеличить производительность при ограниченных аппаратных возможностях. Аппаратные возможности не могут быть сколь угодно большими, плюс размеры файлов могут быть разными...
Имея компонент для буферизированного чтения/записи данных можно не беспокоиться, сколько в такой-то машине ОЗУ, хватит ли ее для чтения файла такого-то размера.
Ты знаешь, сколько ОЗУ требуется для буфера (понятно что это несколько килобайт) и уже ни размер файла, ни размер ОЗУ не важен.
Это очень важно для создания программ, которые будут работать на машинах с различными аппаратными возможностями.
Для создания такого компонента нужно идти от задачи (возможно для задачи копирования файла лучше использовать функции Win32).
Идея буферизации широкого используется и в программах записи CD,DVD и в тех же процессорах, у которых есть свои буфера для хранения данных/команд. Если применяешь обработку какого-то текста, который хранится в файле, то здесь также лучше использовать буферизированное чтение/запись.
У меня, например, реализован лексер, который читает лексемы из файла. Файл может содержать сотни Мб текста, но реально программа будет читать его порциями - по аналогии с TParser из Delphi. Другое дело, что реально проще считать весь файл и затем его обработать :)
Цитата: michael_is_98
1) Смысла нет.
2) Нет не получится.
Весь смысл в буферизации как раз и состоит в том, чтобы увеличить производительность при ограниченных аппаратных возможностях. Аппаратные возможности не могут быть сколь угодно большими, плюс размеры файлов могут быть разными...
А ты учитываешь среди аппаратных ограничений HDD?В ведь от скорости работы дисковой подсистемы многое зависит. Если, как ты говоришь, файл содержит сотни метров данных, которые по нему еще фрагментарно расбросаны..
Иногда это может быть более критичным, чем ОЗУ, мне кажется:)
Тебе нужно лишь продумать буферизацию на уровне своей задачи.И сделать выделение области памяти независимым от размера файла, который будет читаться. Если всегда знаешь, что файл занимает 4 Кб - обходись без буфера. Если у тебя файл может быть большой и очень большой и тебе нужно его весь прочитать и обработать в соответствие со своей задачей - используй буферизированное чтение. Выбери размер буфера равным размеру кластера (4Кб) и все...
Цитата: michael_is_98
Выбери размер буфера равным размеру кластера (4Кб) и все...
А почему не, скажем, 4 мб? если файл занимает 20?
Иди от задачи.
Я использовал буфер 4Кб, потому что размера такого буфера вполне хватит чтобы выделить лексему (ключевое слово,идентификатор,литерал,операцию или пунктуатор) из входного потока.
Если мы хотим определить некий "универсально-оптимальный" размер буфера чтения/записи, так он для каждой задачи и для каждого оборудования свой...
Если мы хотим определить нужен ли буффер как таковой, то нужен, если чтение должно быть либо быстрое, либо ведётся обработка (т.е. чтение, запись, перечтение, перезапись и т.д.) одних и техже данных (файлов, частей файлов и т.д.)
P.S. И вам не кажется, что создатель темы куда пропал....)))))))))
А вообщето буферезация делается и без нас с вами, так что сильно мудрить на эту тему не стоит, не эффективно.
Я бы небольшие файлы читал бы не более 255 байт.Если компилятор поддерж MMX, SSe, SSe2 - то для больших массивов имеет смысл задействовать и большими буферами читать. А так не больше 64 кил
на ПС машине - ограничение архитектуры. Ещё и важен размер кэша на процессоре ...
Цитата: ivanhoeivanhoe
сомневаюсь по этому поводу. Щас винты все с внутренним кэшированием. что 8 кил -что 8 мег получишь с одной сред скоростью.
Я бы небольшие файлы читал бы не более 255 байт.Если компилятор поддерж MMX, SSe, SSe2 - то для больших массивов имеет смысл задействовать и большими буферами читать. А так не больше 64 кил
на ПС машине - ограничение архитектуры. Ещё и важен размер кэша на процессоре ...
Я бы небольшие файлы читал бы не более 255 байт.Если компилятор поддерж MMX, SSe, SSe2 - то для больших массивов имеет смысл задействовать и большими буферами читать. А так не больше 64 кил
на ПС машине - ограничение архитектуры. Ещё и важен размер кэша на процессоре ...
Я только про обмен "диск - память", а буфер при большом чтении нужен для того что бы много раз на диск не лазить,это уже с кодом программы связанно, а не с обменом данными.
Вопрос в том, что частые обращения к жесткому диску вредны. И время на порядок больше нужно. А буфер лежит спокойно в оперативке, и хлеба не просит:).