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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как преобразовать 0x0D в 0x0A? как преобразовать символы конца строк? 
:(
    Опции темы
ddsoft
Дата 17.4.2013, 10:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Подскажите, пожалуйста, как преобразовать конец строк файлов из Windows в Linux. Т.е. надо пару символов 0D 0A файла Windows преобразовать в символ 0A (как ф должно быть в файле Linux)? Нужно на классическом C. Я Делаю так. Открываю исходный файл читаю посимвольно из него и делаю проверку, если идут подряд два символа 0D0A, пишу в целевой файл только 0A. Но такое не работает. В итоге получается точная копия исходного файла. Использовал функции getc() и putc(). Посмотрел, что записывается в считываемый символ. Оказалось, что туда никогда не записывается символ 0D, только 0A. Поэтому и не работает проверка. Но в целевой файл-то пишется правильно и 0D и 0A. Как прочитать символ 0D?
Вот кусок, который читает их исходного файла:
Код

char ch;

while (!feof(input))
    {
        ch=getc(input);
        ............
    }

Непонятно как в переменную ch пишется сразу два байта, т.к. при записы в файл оба байта там есть (0D0A).
PM MAIL   Вверх
math64
Дата 17.4.2013, 10:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Ты в какой операционке это делаешь?
В Линуксе твоя программа будет работать правильно.
А вот в Windows по умолчанию при чтении 0D-0A ("\r\n") будет заменяться на 0A ('\n'),
а при записи - 0A в автомате заменится 0D-0A.
Чтобы этого не было, файл нужно откывать в двоичном режиме:
Код

FILE* input = fopen(inputfilename, "rb");
FILE* output = fopen(outputfilename, "wb");
while (!feof(input))
    {
        ch=fgetc(input);
        ............
        fputc(ch, output);
    }
fclose(input);
fclose(output);

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


Эксперт
****


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

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



Цитата(ddsoft @  17.4.2013,  11:01 Найти цитируемый пост)
Непонятно как в переменную ch пишется сразу два байта, т.к. при записы в файл оба байта там есть (0D0A). 

Ну, Вы же код не привели, поэтому и комментировать нечего.
Побайтовое чтение - не очень эффективно, но пусть будет.

Цитата(ddsoft @  17.4.2013,  11:01 Найти цитируемый пост)
Но в целевой файл-то пишется правильно и 0D и 0A. Как прочитать символ 0D?

Надо просто запоминать, что предыдущий символ был 0D, и если текущий - 0A, то 0D не записывать:
Код

int maybe = 0;
int ch;
while( (ch = fgets(input)) != EOF )
{
  if( ch == '\n' )
  {
    fputc( '\n', output);
    maybe = 0;
  }
  else if( ch == '\r' )
  {
    if( maybe ) fputc( '\r', output);
    maybe = 1;
  }
  else
  {
    if( maybe ) fputc( '\r', output);
    fputc( ch, output);
    maybe = 0;
  }
}
if( maybe ) fputc( '\r', output);

И не забывать проверять ошибки вызовов)))

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


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


Новичок



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

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



Цитата(math64 @  17.4.2013,  10:20 Найти цитируемый пост)
Ты в какой операционке это делаешь?
В Линуксе твоя программа будет работать правильно.
А вот в Windows по умолчанию при чтении 0D-0A ("\r\n") будет заменяться на 0A ('\n'),
а при записи - 0A в автомате заменится 0D-0A.
Чтобы этого не было, файл нужно откывать в двоичном режиме

Я делаю в Windows. Действительно, в линуксе работает как надо.
Это особенность операционки при работе с текстовыми файлами? 
А как-нибудь можно, при работе с текстовыми файлами, указать в Windows, что не надо заменять при чтении 0D-0A на 0A?
Да, при открытии в двоичном режиме всё работает. Спасибо!

Это сообщение отредактировал(а) ddsoft - 18.4.2013, 06:59
PM MAIL   Вверх
ddsoft
Дата 17.4.2013, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(feodorv @  17.4.2013,  10:23 Найти цитируемый пост)
Ну, Вы же код не привели, поэтому и комментировать нечего.

Привожу код, преобразующий символы конца срок из Windows формата в Linux формат:
Код

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

int main(int argc, char *argv[])
{
    char ch;
    FILE *input, *output;
    input=fopen("input.txt","r+");
    output=fopen("output.txt","w+");
    if (input==NULL)
    {
        printf("Source file not found or can not be opened.\n");
        return -1;
    }
    while (!feof(input))
    {
        ch=getc(input);
        if (!feof(input)) if (ch!=0x0D) putc(ch, output);        
    }
    fclose(input);
    fclose(output);
    return 0;
}


Цитата(feodorv @  17.4.2013,  10:23 Найти цитируемый пост)
Побайтовое чтение - не очень эффективно

А как посоветуете сделать эффективнее?

Цитата(feodorv @  17.4.2013,  10:23 Найти цитируемый пост)
Надо просто запоминать, что предыдущий символ был 0D, и если текущий - 0A, то 0D не записывать

Обнаружить символ 0D не получилось при открытии файла в текстовом режиме.
А когда я поменял строки
Код

    input=fopen("input.txt","r+");
    output=fopen("output.txt","w+");

на строки
Код

    input=fopen("input.txt","rb");
    output=fopen("output.txt","wb");

всё заработало как надо.

Цитата(feodorv @  17.4.2013,  10:23 Найти цитируемый пост)
  if( ch == '\n' )
  {
    fputc( '\n', output);
    maybe = 0;
  }

Мне такой код писал сразу два байта (\r\n) в файл, открытый в текстовом режиме.

Цитата(feodorv @  17.4.2013,  10:23 Найти цитируемый пост)
  else if( ch == '\r' )
  {
    if( maybe ) fputc( '\r', output);
    maybe = 1;
  }

А такой код у меня совсем не выполнялся.

Это сообщение отредактировал(а) ddsoft - 17.4.2013, 23:10
PM MAIL   Вверх
volatile
Дата 18.4.2013, 00:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



можно логику упростить. просто игнорировать 0xd, и все. 
PM MAIL   Вверх
feodorv
Дата 18.4.2013, 04:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(ddsoft @  18.4.2013,  00:09 Найти цитируемый пост)
А как посоветуете сделать эффективнее?

Читайте, например, по 4 килобайта, выбрасывайте из буфера '\r' (длина буфера уменьшится), записывайте получившийся буфер... 

Цитата(ddsoft @  18.4.2013,  00:09 Найти цитируемый пост)
Мне такой код писал сразу два байта (\r\n) в файл, открытый в текстовом режиме.

Ну, с этим уже разобрались  smile Фича такая у стандартной библиотеки от MS... Вот здесь человеку ещё хуже пришлось...



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


Новичок



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

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



Цитата(volatile @  18.4.2013,  00:18 Найти цитируемый пост)
можно логику упростить. просто игнорировать 0xd, и все.  

Что вы имеете ввиду? Можно поподробнее, пожалуйста?

Добавлено @ 06:55
Цитата(feodorv @  18.4.2013,  04:34 Найти цитируемый пост)
Цитата(ddsoft @  18.4.2013,  00:09)
А как посоветуете сделать эффективнее?

Читайте, например, по 4 килобайта, выбрасывайте из буфера '\r' (длина буфера уменьшится), записывайте получившийся буфер... 

А что будет, если длина буфера окажется больше оставшегося куска файла? Автоматически буфер будет подгоняться под размер оствшегося куска файла или целевой файл окажется длиннее исходного на длину остатка буфера?

Это сообщение отредактировал(а) ddsoft - 18.4.2013, 06:56
PM MAIL   Вверх
feodorv
Дата 18.4.2013, 08:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(ddsoft @  18.4.2013,  07:50 Найти цитируемый пост)
А что будет, если длина буфера окажется больше оставшегося куска файла?

Не понял, как это... Договорились же открывать файлы в бинарной моде, там чтение 1 в 1... Вот скелет алгоритма:
Код

int count, i, j;
while( (count = fread( buffer, 1, sizeof(buffer), input)) > 0 )
{
  for( i = j = 0; i < count; i++) 
    if( buffer[i] != '\r' ) buffer[j++] = buffer[i];
  if( j > 0 ) fwrite( buffer, 1, j, output);
}



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


Эксперт
****


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

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



Ну можно открыть файл в текстовом режиме, прочитать всё, и записать двоичном. Но так можно только в Windows, в Linux получите на выходе копию входного файла, поскольку там текстовый и двоичный режим не отличаются.

При чтении же в текстовом режиме режиме 0D не игнорируется
0D 0A  и 0A 0D (стандарт MAC) заменяются на 0A.
Одиночный 0D нужно либо оставлять так, либо заменять на 0A (есть ОС, в которых для разделения строк использется 0D)
PM   Вверх
xvr
Дата 18.4.2013, 10:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Цитата(ddsoft @  17.4.2013,  23:09 Найти цитируемый пост)
Привожу код, преобразующий символы конца срок из Windows формата в Linux формат:

Как правильно заметил math64 код можно несколько упростить:
Код

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    int ch;
    FILE *input, *output;
    input=fopen("input.txt","rt");
    output=fopen("output.txt","wb");
    if (input==NULL)
    {
        printf("Source file not found or can not be opened.\n");
        return -1;
    }
    if (output==NULL)
    {
        printf("Can't create output file.\n");
        return -1;
    }
    while ( (ch=getc(input)) != EOF) putc(ch, output);        
    fclose(input);
    fclose(output);
    return 0;
}

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


Новичок



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

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



Цитата(feodorv @  18.4.2013,  08:25 Найти цитируемый пост)
Цитата(ddsoft @  18.4.2013,  07:50 )
А что будет, если длина буфера окажется больше оставшегося куска файла?

Не понял, как это... Договорились же открывать файлы в бинарной моде, там чтение 1 в 1... 

Я имел ввиду, что если буфер 4 килобайта, а файл 10 килобайт, то при двукратной записи буфера в файл,
весь файл ещё не перепишется, а при трёхкратной целевой файл окажется уже 12 килобайт вместо 10 килобайт.
По вашему коду теперь понял, что записываться будет только количество реально прочитанных байт.

Цитата(math64 @  18.4.2013,  09:05 Найти цитируемый пост)
Ну можно открыть файл в текстовом режиме, прочитать всё, и записать двоичном.

Я об этом не подумал. Спасибо за наводку smile 

Цитата(xvr @  18.4.2013,  10:10 Найти цитируемый пост)
Как правильно заметил math64 код можно несколько упростить

Спасибо!
PM MAIL   Вверх
volatile
Дата 18.4.2013, 23:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(math64 @  18.4.2013,  09:05 Найти цитируемый пост)
При чтении же в текстовом режиме режиме 0D не игнорируется
0D 0A  и 0A 0D (стандарт MAC) заменяются на 0A.
Одиночный 0D нужно либо оставлять так, либо заменять на 0A (есть ОС, в которых для разделения строк использется 0D) 

При преобравании виндозных файлов можно просто игнорировать. 
Если -же пишецца универсальный конвертер текстовых файлов любых операционок, то ни одна программа приведенная здесь работать правильно все равно не будет.  smile 

PM MAIL   Вверх
ddsoft
Дата 19.4.2013, 11:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Допилил программу. Программа работает в windows и linux, преобразовывает концы строк win->unix и unix->win, имеет 3 входных параметра: 1) режим преобразования (win->unix или unix->win); 2) исходный файл; 3) целевой файл. Как на ваш взгляд можно сделать оптимальнее? Вот что у меня получилось:
Код

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char ch;
    FILE *input, *output;
    int value; //возвращаемое функцией main значение

    if (argc<3) //если не хватает параметров
    {
        printf("too few parameters to program.\n");
        printf("usage: program <change_mode> <source_file> <destination_file>\n");
        printf("change_mode = (win2nix, nix2win)\n");
    }
    else
    {
        input=fopen(argv[2],"rb");
        output=fopen(argv[3],"wb");
        if (input==NULL)
        {
            printf("Source file is not found or can not be opened.\n\n...end.");
            value = -1;
        }
        else
        {
            while (!feof(input)) // Пока не конец файла
            {
                ch=getc(input);
                if (!feof(input))
                {
                    if (strcmp(argv[1], "win2nix")==0)
                      if (ch!=0x0D) putc(ch, output); //пишем всё, кроме символа возврата каретки, в целевой файл
                    if (strcmp(argv[1], "nix2win")==0)
                     if (ch!=0x0D) //проверка на случай, если преобразовываться будет файл не с unix концом строки, а с windows концом строки (иначе в файле будут копиться лишние символы 0x0D)
                     {
                       if (ch==0x0A) //если встречаем unix символ конца строки,
                       {
                           //пишем к нему ещё перевод каретки для windows конца строки
                           putc(0x0D, output); putc(ch, output);
                       }
                       else putc(ch, output); //иначе просто пишем очередной символ
                     }
                }
            }
            fclose(input);
            fclose(output);
            value = 0;
        }
    }
    return value;
}

PM MAIL   Вверх
xvr
Дата 19.4.2013, 12:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Цитата(ddsoft @  19.4.2013,  11:19 Найти цитируемый пост)
 Как на ваш взгляд можно сделать оптимальнее?

Можно, причем существенно оптимальнее. И вам тут уже говорили как именно  smile 

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

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

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

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

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


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

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


 




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


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

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