Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Подсчитать размер файла (как лучше?)  (Прочитано 22533 раз)
0 Пользователей и 1 Гость смотрят эту тему.
lightmaker
Участник

ru
Offline Offline

« : 16-02-2008 19:34 » 

Собсно имеется текстовый файл (или бинарный, не важно) и требуется получить его размер.
В голову пришло только следующее:

char buf[256];
unsigned size=0, tmp;
......
for( ; ; ){
  tmp=fread(buf,1,256,fp);
  size+=tmp;
  if(tmp<256) break;
}
......
В итоге получили размер файла в лице size Улыбаюсь
Смущает в первую очередь то, что функция fread при возникновении ошибки также возвращает значение меньшее, чем счетчик. И не ясно, толи достигут конец файла и, поэтому считано меньше, чем счетчик или возникла ошибка.

Как сделать лучше?
Заранее спасибо.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 16-02-2008 19:46 » 

lightmaker, проще: stat или fstat.
Вот в POSIX
В винде
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #2 : 17-02-2008 06:52 » new

lightmaker, еще можно сделать fseek от конца файла, а потом получить pos Улыбаюсь
Записан

Странно всё это....
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 17-02-2008 10:22 » 

LogRus, извращенец  Внимание! Говорит и показывает...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 17-02-2008 10:39 » 

Согласен с RXL, лучше пользоваться специальными функциями для получения информации о файле Улыбаюсь
lightmaker не указал нам платформу, для которой это делает. Если это Win, то если не нужна кросс-платформенность, возможно, проще будет воспользоваться CreateFile для открытия файла и GetFileSize для получения размера
Записан
lightmaker
Участник

ru
Offline Offline

« Ответ #5 : 17-02-2008 10:55 » 

Спасибо за ответы.
Пишу под Linux. Прочитал про stat, fstat, но хочется обойтись без подключения доп. библиотек. Хотя, если этого требует хороший тон и т.д. то можно и с ними.
Товарисч LogRus действительно извращенец. Улыбаюсь Но я последовал половине его совета, поставил указатель в конец файла и использовал ftell.
А задача у меня вообще такая, есть некий конфигурациооный файл, количество и размер строк (параметров) заранее не известно. Нужно на его основе забить массив структур. Я решил взять его размер и считать инфу в динам. массив, для последующий с ним работы.
Может быть эту задачу можно решить эффективней? Посоветуйте пож-та.
« Последнее редактирование: 17-02-2008 11:02 от lightmaker » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 17-02-2008 11:35 » 

lightmaker, glibc трудно назвать дополнительной библиотекой Ага
Более того, данные можно получить без библиотеки, напрямую обращаясь к системным вызовам, но это решение может оказаться не кроссплатформенным.

Разбор конфига лучше делать построчным чтением и последующей интерпретацией строк. Знать размер файла для этого необходимости нет. Читать весь файл в память - не лучшее решение.
Смотри ф-ии fgets и подобные.

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

"Массив структур". Следует заранее выделить с запасом, или применить динамическое выделение. Напрямер, использовать связанные списки. Очень полезная вещь - STL, но это С++.
« Последнее редактирование: 17-02-2008 11:37 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 17-02-2008 11:56 » 

Примерно так можно решить.

Код: (C++)
#include <stdio.h>
#include <map>

typedef std::map <std::string, std::string> map_string_by_string_t;

#define STRING_SIZE_MAX 1024

int main()
{
    map_string_by_string_t config;
    FILE *f;
    char s[STRING_SIZE_MAX];
    std::string key, value;

    f = fopen("file", "r");
    while (fgets(s, STRING_SIZE_MAX, f))
    {
        // разбор строки типа key=value (здесь не преведен)
        // результат помещаем в переменные key и value

        // сохраняем пару в конфиге
        config[key] = value;
    }

    // обращаемся к значению в конфиге
    value = config[key];

    // .....

    return 0;
}

Более сложный формат конфига потребует более сложного решения. Логика всегда поможет.
« Последнее редактирование: 17-02-2008 11:57 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lightmaker
Участник

ru
Offline Offline

« Ответ #8 : 17-02-2008 13:06 » 

Не могли бы вы пояснить строчку:
typedef std::map <std::string, std::string> map_string_by_string_t;
Просто я на С++ с С только только перехожу.

А если строчка окажеться более 1024, заранее длину не могу предположить.

И почему считывать все сразу в память не самое лучшее решение? Ведь в этом случае мы только один раз обращаемся к диску.
Спасибо за терпение:)
« Последнее редактирование: 17-02-2008 13:38 от lightmaker » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 17-02-2008 13:49 » 

lightmaker, это не готовый код, а только пример. Шаблон STL map показан только для примера. реализовать такое можно и без STL и С++.

STL - это библиотека шаблонов для C++ (Standart Template Library).

Для удобства подкрасил части.
typedef std::map <std::string, std::string> map_string_by_string_t;

1. Синий. typedef - ключевое слово для определения пользовательского типа.
2. Красный. Имя шаблона. std - это пространство имен. map - имя класса-шаблона.
3. Зеленый. Первый аргумент шаблона - ключ. В данном случае это тоже тип из STL - строка.
4. Оранжевый. Второй аргумент шаблона - значение.
5. Фиолетовый. Имя определяемого типа.

В итоге, тип map_string_by_string_t означает: ассоциативный контейнер, содержащий строки, индексированные строками.

Есть у нас статья, но для начинающего она не подойдет: https://club.shelek.ru/viewart.php?id=96 .
Лучше почитать описание STL или самоучитель.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lightmaker
Участник

ru
Offline Offline

« Ответ #10 : 17-02-2008 19:26 » 

Спасибо! Буду читать про STL;
А как насчет:

"А если строчка окажеться более 1024, заранее длину не могу предположить.

И почему считывать все сразу в память не самое лучшее решение? Ведь в этом случае мы только один раз обращаемся к диску."
Спасибо снова за терпение:)
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 17-02-2008 19:31 » 

lightmaker, если не знаешь размера строки, то читай посимвольно или используй файловые потоки ввода-вывода (fstream).
А читать целиком идея плохая, потому что попадётся тебе слишком крупный файл (по ошибке или ещё как) - только память зря забьёшь, или просто памяти не хватит на то, чтобы загрузить всё.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #12 : 17-02-2008 22:15 » 

Функции streaming IO, куда входят fopen, fclose, fread, fwrite, fputs и т.п., используют буферизированный  ввод-вывод и разницы в скорости ты не заметишь. Ведь по сути - что указателем познать по байтам, что построчно читать из буфера - принцип и скорость одна. Зато расход памяти минимален и способ универсальный. Чтение же файла целиком для текста - излишество. Нет, это никто не запрещает, но смысла нет. Подсунет кто-нибудь (может быть и не со зла) твоей программе вместо конфига образ dvd размером гиг 8. Думаю, что после нескольких минут свопирования программа завершится с ошибкой.
Кстати, о расходе памяти. Ее надо экономить как воду - программа не одна на компе и всем хочется кушать.

На случай, если строка больше 1кБ, то есть решение только для GNU (glibc) - см. pinfo libc. Есть такая ф-ия getline.
Код: (C)
size_t getline(char **LINEPTR, size_t *N, FILE *STREAM)
Эта ф-ия сама выделит столько памяти, сколько потребуется твоей строке: если буфер мал - она его увеличит, если память вообще не выделена - сама это сделает. Просто сказка, а не ф-ия. Обязательно прочти мануал перед использованием. Ф-ия работает с динамической памятью.
« Последнее редактирование: 17-02-2008 22:21 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #13 : 18-02-2008 08:59 » 

RXL, раз C++ то ведзе
максимальную длинну строки в топку
открываем файл через ifstream ifs("FILE.TXT");
читаем строки через getline(ifs,line);
или ifs >> line;
getline удобней в ряде случаев.

Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines