Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> fscanf как работает? fprintf - понятно, fscanf - нет 
V
    Опции темы
nns2009
Дата 14.2.2009, 13:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 1.2.2009

Репутация: нет
Всего: 1



У меня программа должна уметь сохранять, а через некоторое время читать информацию из файла в формате .csv(значения разделённые ;).
(Чтобы можно было через Excel открывать).
В файле хранится:
версия программы,
количество типов содержимого ячеек таблицы,
типы содержимого ячеек таблицы,
размер таблицы,
таблица
В общем, пример содержимого файла я прикрепил.

Его создаёт такой код
Код

void SaveTable()
{
    int wotf = max(5, width_of_table);
    char* table_string = new char[4*width_of_table];
    table_string[0] = 0;
    FILE* file;
    file = fopen(file_name, "w");
        char* point_w_z = new char[wotf];
        for (int i = 0; i < wotf-1; i++)
            point_w_z[i] = ';' ;
        point_w_z[wotf-1] = 0;
        fprintf(file, "V %g%s\n", 1.0, point_w_z);
        fprintf(file, "%d%s\n", number_of_pases, point_w_z);

        point_w_z[wotf-5] = 0;
        for (int i = 0; i < number_of_pases; i++)
            fprintf(file, "%d;%d;%d;%s;%s%s\n", pases[i].r, pases[i].g, pases[i].b, pases[i].name, pases[i].description, point_w_z);
        point_w_z[wotf-5] = ';';

        point_w_z[wotf-2] = 0;
        fprintf(file, "%d;%d%s\n", width_of_table, height_of_table, point_w_z);
        point_w_z[wotf-2] = ';';

        char decimal[3];
        for (int i = 0; i < height_of_table; i++)
        {
            for (int j = 0; j < width_of_table; j++)
            {
                itoa(table[i][j], decimal, 10);
                strcat(table_string, decimal);
                if (j != width_of_table-1) strcat(table_string, ";");
            }
            fprintf(file, "%s\n", table_string);
            table_string[0] = 0;
        }
    fclose(file);
    delete [] table_string;
}


Вопрос в том, как можно произвести обратное действие?
1. Можно построчно читать файл и разбирать строки на составляющие вручную.
2. Думаю с помощью функции fscanf() это можно реализовать удобнее, но как?
На сколько я понял сканф останавливает сканирование как только находит пробел и уже при первом вызове, строка, которую он создаёт, содержит только один символ "V"(что для меня не очень удобно).

Это сообщение отредактировал(а) nns2009 - 14.2.2009, 13:20

Присоединённый файл ( Кол-во скачиваний: 7 )
Присоединённый файл  first.txt 0,68 Kb
PM MAIL   Вверх
andrew_121
Дата 14.2.2009, 18:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодофей
****


Профиль
Группа: Завсегдатай
Сообщений: 3448
Регистрация: 3.1.2008

Репутация: 6
Всего: 33



Цитата(nns2009 @  14.2.2009,  13:17 Найти цитируемый пост)
На сколько я понял сканф останавливает сканирование как только находит пробел

Не верно!


--------------------
Удалил аккаунт. Прощайте!
PM MAIL   Вверх
Earnest
Дата 15.2.2009, 16:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



csv-файл удобнее всего читать построчно и разбирать каждую строку на лексемы, разделеные заданным символом (;). Это элементарно написать самому, но есть и готовые функции, нарпимер strtok. А уже отдельные слова интерпретировать вообще пустяк. scanf удобно использовать тогда, когда формат абсолютно фиксирован и точно известен. 


--------------------
...
PM   Вверх
nns2009
Дата 16.2.2009, 15:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 1.2.2009

Репутация: нет
Всего: 1



Цитата(Earnest @  15.2.2009,  16:44 Найти цитируемый пост)
scanf удобно использовать тогда, когда формат абсолютно фиксирован и точно известен.  

А разве у меня формат не фиксирован? :

версия
количество данных
данные
количество данных
данные

Каждая часть данных записывается на отдельной строке в одинаковом формате.
Ну, если что буду разбирать построчно.
PM MAIL   Вверх
Earnest
Дата 16.2.2009, 18:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(nns2009 @  16.2.2009,  16:17 Найти цитируемый пост)
А разве у меня формат не фиксирован? :

Если есть "кол-во данных", а потом "данные" в этом самом количестве, то нет. Как ты формат для scanf запишешь, если во время компиляции неизвестно сколько "данных" читать? Ну то есть можно поизвращаться, но разбор на лексемы проще и нагляднее по результирующему коду.


--------------------
...
PM   Вверх
nns2009
Дата 16.2.2009, 23:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 1.2.2009

Репутация: нет
Всего: 1



Цитата(Earnest @  16.2.2009,  18:15 Найти цитируемый пост)
Если есть "кол-во данных", а потом "данные" в этом самом количестве, то нет.

Но ведь по идее данные серавно читаются в цикле, даже если их известное количество изначально, а внутренняя часть цикла одинакова
для известного числа чтений:

Код

int number = 7;
for (int i = 0; i < number; i++)
{
    чтение_данных(откуда, формат, куда[i])
}
и для неизвестного:

Код

int number =   ...   ;
for (int i = 0; i < number; i++)
{
    чтение_данных(откуда, формат, куда[i])
}

Можете привести пример кода(с использованием fscanf()), который читает данные из файла, созданного функцией SaveTable() (в моём первом сообщении) для определённого числа данных, предположим трёх.
PM MAIL   Вверх
inside_pointer
Дата 17.2.2009, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 9.3.2008

Репутация: 5
Всего: 12



через strtok


Присоединённый файл ( Кол-во скачиваний: 5 )
Присоединённый файл  parse.tar 20,00 Kb
PM MAIL   Вверх
inside_pointer
Дата 17.2.2009, 13:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 9.3.2008

Репутация: 5
Всего: 12



вывод
Код

[guest@station test]$ cc *.c -o parse
[guest@station test]$ ./parse
V 1;;;;;;;;;;;;;;;;;;;;;;;
4;;;;;;;;;;;;;;;;;;;;;;;
255;255;255;Не заполнено;Не заполнено;;;;;;;;;;;;;;;;;;;
255;0;0;Отдых;В это время работник может отдыхать.;;;;;;;;;;;;;;;;;;;
0;255;0;Работа;В это время работник обязан работать.;;;;;;;;;;;;;;;;;;;
0;0;255;Обед;В это время работник может обедать.;;;;;;;;;;;;;;;;;;;
24;7;;;;;;;;;;;;;;;;;;;;;;
3;2;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;2;3
2;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;2
0;1;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;1;0
0;1;3;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;3;1;0
0;1;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;1;0
2;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;2
3;2;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;2;3

 V 1
4
255 255 255 Не заполнено Не заполнено
255 0 0 Отдых В это время работник может отдыхать.
0 255 0 Работа В это время работник обязан работать.
0 0 255 Обед В это время работник может обедать.
24 7
3 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3
2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
0 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 0
0 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 0
0 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 0
2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
3 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3

[guest@station test]$



Это сообщение отредактировал(а) inside_pointer - 17.2.2009, 13:44
PM MAIL   Вверх
inside_pointer
Дата 18.2.2009, 05:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 9.3.2008

Репутация: 5
Всего: 12



подредактировал чтобы читала построчно и разбирала каждую строку через strtok

вывод
Код

[guest@station parse]$ cc *.c -o parse
[guest@station parse]$ ./parse
 V 1;;;;;;;;;;;;;;;;;;;;;;;
 V 1

 4;;;;;;;;;;;;;;;;;;;;;;;
 4

 255;255;255;Не заполнено;Не заполнено;;;;;;;;;;;;;;;;;;;
 255 255 255 Не заполнено Не заполнено

 255;0;0;Отдых;В это время работник может отдыхать.;;;;;;;;;;;;;;;;;;;
 255 0 0 Отдых В это время работник может отдыхать.

 0;255;0;Работа;В это время работник обязан работать.;;;;;;;;;;;;;;;;;;;
 0 255 0 Работа В это время работник обязан работать.

 0;0;255;Обед;В это время работник может обедать.;;;;;;;;;;;;;;;;;;;
 0 0 255 Обед В это время работник может обедать.

 24;7;;;;;;;;;;;;;;;;;;;;;;
 24 7

 3;2;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;2;3
 3 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3

 2;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;2
 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2

 0;1;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;1;0
 0 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 0

 0;1;3;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;3;1;0
 0 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 0

 0;1;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;1;0
 0 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 0

 2;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;2
 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2

 3;2;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;2;3
 3 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3

[guest@station parse]$          

ни strtok ни fscanf не могут залезть между ;; и вывести, что там ничего нет, если юзать fscanf, её работа будет сведена к посимвольному разбору (то есть то же самое, что просто символы анализировать); многие путают и думают что fscanf это обратный аналог к fprintf, на самом деле это совершенно различные функции и их следует изучать по отдельности, иначе будет путаница

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  parse_mod.tar 20,00 Kb
PM MAIL   Вверх
Earnest
Дата 18.2.2009, 10:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(inside_pointer @  18.2.2009,  06:06 Найти цитируемый пост)
ни strtok ни fscanf не могут залезть между ;; и вывести, что там ничего нет

strtok может, а вот scanf действительно нет.


--------------------
...
PM   Вверх
nns2009
Дата 19.2.2009, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 1.2.2009

Репутация: нет
Всего: 1



Цитата(inside_pointer @  18.2.2009,  05:06 Найти цитируемый пост)
многие путают и думают что fscanf это обратный аналог к fprintf, на самом деле это совершенно различные функции и их следует изучать по отдельности

Я тоже так думал. А есть ли тогда обратный аналог fprintf();

Код

char *ParseLine(char *s, const char *delim)
{
    static int state = 0;
    char *p;
    
    if (state == 0) {
        state = 1;
        p = strtok(s, delim);
    } else
        p = strtok(NULL, delim);
    if (p == NULL)
        state = 0;
    return p;    
}

На сколько я понял strtok();  возвращает строку до разделителя, а в строке, переданной через параметр, обрезает её с разделителем

Код

FILE *OpenFile(const char *fname)
{
    return fopen(fname, "rb");
}
int CloseFile(FILE *fp)
{
    if (fp == NULL)
        return EOF;
    return fclose(fp);
}

А зачем эти функции были написаны?

А также зачем вот это:
Print("");

Это сообщение отредактировал(а) nns2009 - 19.2.2009, 15:37
PM MAIL   Вверх
inside_pointer
Дата 20.2.2009, 05:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 9.3.2008

Репутация: 5
Всего: 12



новая версия теперь через fscanf (сохраняет лексемы в массив, выводит пустоты как пустоты)

Код

[guest@station parse2]$ ./parse
 V 1 empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty 1
 empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty 1
 255 255 Не заполнено Не заполнено empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty 1
 0 0 Отдых В это время работник может отдыхать. empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty 1
 255 0 Работа В это время работник обязан работать. empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty 1
 0 255 Обед В это время работник может обедать. empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty 1
 7 empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty empty 1
 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1
 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 1
 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1
[guest@station parse2]$


strtok не может пролезть между ;;;, т.к. она вместо каждого разделителя записывает нуль-символ и переводит указатель поиска на следующую лексему после него, если встречает конец строки возвращает нулевой указатель

Добавлено через 2 минуты и 11 секунд
Цитата(nns2009)

Я тоже так думал. А есть ли тогда обратный аналог fprintf();

она может вывести что угодно, то есть множество обратных аналогов стремится к бесконечности, потому наверное и нету

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  parse2.tar 20,00 Kb
PM MAIL   Вверх
inside_pointer
Дата 20.2.2009, 06:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 9.3.2008

Репутация: 5
Всего: 12



там баг с последним значением
PM MAIL   Вверх
Earnest
Дата 20.2.2009, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(inside_pointer @  20.2.2009,  06:36 Найти цитируемый пост)
strtok не может пролезть между ;;;, т.к. она вместо каждого разделителя записывает нуль-символ и переводит указатель поиска на 

Бог ты мой какие сложности! smile Во-первых, ничего она не "переводит", а просто возвращает следующий за разделителем символ: что делать с этим возвратом - твое дело. Предыдущий симовл-разделитель забит нулем, и в чем здесь проблема? Текущий указатель опять содержит разделитель - т.е. следующая лексема будет пустой. Кстати, есть еще функция strpbrk, которую удобно использовать для тех же целей. 



--------------------
...
PM   Вверх
math64
Дата 20.2.2009, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



strtok() заменяет разделители нулями, поэтому если есть разные разделители, невозожно определить какой он был.
Кроме того, он портит исходную строку, поэтому иногда её нужно предварительно скопировать.
Другие функции, которые можно использовать вместо неё для поиска разделителей: strspn(), strcspn(), strchr(), strstr()
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0692 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.