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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Непонятное считывание файла, Непонятное считывание файла. СИ 
:(
    Опции темы
GQU
Дата 1.9.2015, 11:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Почему функция в программе начинает работу со считывания символа '\n', а не EOF?
В 666.txt содержится:
1
2
3
4
(знака ENTER после 4 нет, пробелов вообще нет)
Код

#include "stdio.h"
#include "stdlib.h"

int f_pos;

void show_console(){
    printf("f_pos = %d \n", f_pos);
}


void test(const char* in_str){
    int ichar;
    FILE* fp;
    fopen_s(&fp, in_str, "r");
    fseek(fp, f_pos, SEEK_SET);
    for (;;){
        ichar = getc(fp);
        char ch = ichar;
        if (ichar == EOF)    { break; }
        f_pos++;
    }
    fclose(fp);
}


int Rlast(){
    char in_char;
    fflush(stdin);
    in_char = getchar();
    if (in_char == '1')    return 1;
    else return 0;
}



void main(){

    do{
        test("666.txt");
        show_console();

    } while (Rlast());


    system("pause");
};


Это сообщение отредактировал(а) GQU - 1.9.2015, 11:21
PM MAIL   Вверх
math64
Дата 1.9.2015, 11:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



1. f_pos не инициализируется. В большинстве компиряторов оно будет 0, но не всегда.
2. Если ОС Windows, то разделитель строк - '\r' '\n' (0x0D 0x0A),
но при открытии fopen в решиме "r"
'\r' будут пропускаться.
Поэтому f_pos будет меньше размера файла.
Чтобы '\r' не пропускались, нужно открывать в режиме "rb".
PM   Вверх
GQU
Дата 1.9.2015, 14:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Все равно не до конца понял, 
Файл в режиме "r" открывается так:
1, \n ,2, \n, 3 ,\n, 4, EOF
После того, как отработала функция, мы в позиции 7(сохраняется в глобальную f_pos), начиная с 0, мы с символа EOF должны начать читать символы, когда следующий раз зайдем в функцию test(), а не с \n, почему читается другой символ?


Это сообщение отредактировал(а) GQU - 1.9.2015, 14:32
PM MAIL   Вверх
volatile
Дата 1.9.2015, 15:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 16
Всего: 85



GQU, 
В win считываетcся 2 байта (\r\n), а в программу дается только один (\n)
Поэтому ваш счетчик не отвечает реальному положению в файле.

Нужно либо открывать в бинарном виде
Цитата(math64 @  1.9.2015,  11:52 Найти цитируемый пост)
в режиме "rb". 


Либо получать текущую позицию из  ftell()


PM MAIL   Вверх
GQU
Дата 1.9.2015, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Напишу может кому пригодится(сам потом читаю smile ):
Реальное положене дел в файле
1,0D,0A,2,0D,0A,3,0D,0A,4,EOF
Как видит программа и мы в отладчике
1,\n,2,\n,3,\n,4,EOF
Я считал, что на позиции 8 EOF, а на самом деле там был 0D

Это сообщение отредактировал(а) GQU - 1.9.2015, 16:06
PM MAIL   Вверх
math64
Дата 2.9.2015, 07:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Реально в файле EOF нет - это такой же искусственный символ, как и выкидывaние 0D ('\r') при чтении в режиме "r".
Как было уже сказано, позицию нужно получать через ftell(), а не считать самому.
Если нужно получать '\r', нужно открывать в режиме "rb" (бинарный для чтения).
В текстовом режиме ("r") также чтение файла остановится, и получим EOF, если встретится 1C (Ctrl-Z)

Это сообщение отредактировал(а) math64 - 2.9.2015, 07:53
PM   Вверх
GQU
Дата 2.9.2015, 08:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата

Реально в файле EOF нет - это такой же искусственный символ, как и выкидывaние 0D ('\r') при чтении в режиме "r".

А выкидывание \r на каком этапе происходит, это дело рук fgetc?
если бы это делал fopen, то когда 2-ой раз заходили в функцию, все позиции f_pos бы совпадали  

Цитата

Как было уже сказано, позицию нужно получать через ftell(), а не считать самому.

Не обязательно использовать ftell, я и без него обошелся, нужно просто добавить условие, что если ichar==10, то смещаемся на 2 позиции

Вот, можете проверить, программа по порциям выводит символы из текстового файла и показывает, сколько процентов осталось, в консоле нужно набрать имя файла, например 666.txt
Код

#include "stdio.h"
#include "stdlib.h"
#include <windows.h>

#define OUT_BUFF 20
int f_pos = 0;
double fake_f_pos = 0;



int quality_gf(char* in_str){
    FILE fp;
    fopen_s(&fp, in_str, "r");
    if (fopen_s(&fp, in_str, "r") == NULL)    return 1;
    else return 0;
}


void get_file(char* in_str, int in_len){
    int in_char;
    int i = 0;
    while ((i < in_len) && (in_char = getchar()) != '\n'){
        in_str[i] = in_char;
        i++;
    }
    in_str[i] = '\0';
}

double f_persent(int f_pos, char* in_str){
    double persent;
    double fake_count_char = 0;
    int ichar;
    double full_count_char = 0.0;
    FILE* fp;
    fopen_s(&fp, in_str, "r");
    while (1)    {
        ichar = getc(fp);
        if (ichar == -1) break;
        if (ichar == 10)    full_count_char+=2;
        else full_count_char++;
        fake_count_char++;
    }
    persent = (100.0 - (fake_f_pos / (fake_count_char / 100)));
    return persent;
}


void show_console(char* in_str, char* out_str){
    int i = 0;
    double persent;
    if (out_str[0] == '\0')    { system("color 0C"); system("cls"); printf("Bol'she nu4ego net!"); }
    printf("%s    \n", out_str);
    persent = f_persent(f_pos, in_str);
    printf("Ostalos' %f\%\%        \n", persent);
    printf("More?(1-Yes) \n");

}


int Rlast(){
    char in_char;
    fflush(stdin);
    in_char = getchar();
    if (in_char == '1')    return 1;
    else return 0;
}


void f_read(const char* in_str, char* out_str, int out_len){
    int i;
    int number_char = 0;
    int ichar;
    FILE* fp;
    fopen_s(&fp, in_str, "r");
    fseek(fp, f_pos, SEEK_SET);
    for (i = 0; i < out_len; i++){
        ichar = fgetc(fp);
        if (ichar == EOF)    { break; }
        out_str[i] = ichar;
        if (ichar == 10)  f_pos += 2;
        else f_pos++;
        fake_f_pos++;
    }
    out_str[i] = '\0';

    fclose(fp);
}

void main(){
    char out_str[OUT_BUFF];
    char in_str[255];
    get_file(in_str, sizeof(in_str)-1);
    if (quality_gf(in_str)){
        do{
            f_read(in_str, out_str, sizeof(out_str)-1);
            show_console(in_str, out_str);
        } while (Rlast());
    }
    else printf("File NOT FOUND!    \n");
    system("pause");
};


Это сообщение отредактировал(а) GQU - 2.9.2015, 08:39
PM MAIL   Вверх
feodorv
Дата 2.9.2015, 09:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

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



Цитата(GQU @  2.9.2015,  08:20 Найти цитируемый пост)
если ichar==10, то смещаемся на 2 позиции

Это не верно. Если, не дай Бог, в файле встретится просто '\n' без '\r', то смещая на 2, Вы совершите ошибку.


Непонятное упрямство. Если Вам важны смещения, то открывайте файл в бинарной моде "rb", тогда он будет считываться таким, каков он есть. И все смещения будут правильными.

Это сообщение отредактировал(а) feodorv - 2.9.2015, 10:00


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
math64
Дата 2.9.2015, 13:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(GQU @  2.9.2015,  08:20 Найти цитируемый пост)
А выкидывание \r на каком этапе происходит, это дело рук fgetc?

При открытии файла с помощью fopen() запоминается режим работы (бинарный или текстовый) и выделяется пустой буфер. При чтении fgetc() или другой функцией, если буфер пуст, считывется порция файла в буфер. '\r' могут выкидиваться сразу после заполнения буфера или при каждом чтении - в зависимости от реализации. Как конкретно в вашем случае - можно посмотреть отладчиком в переменной fp после первого fgetc().

PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


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

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


 




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


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

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