| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Для новичков > Как преобразовать 0x0D в 0x0A? |
| Автор: ddsoft 17.4.2013, 10:01 | ||
| Подскажите, пожалуйста, как преобразовать конец строк файлов из Windows в Linux. Т.е. надо пару символов 0D 0A файла Windows преобразовать в символ 0A (как ф должно быть в файле Linux)? Нужно на классическом C. Я Делаю так. Открываю исходный файл читаю посимвольно из него и делаю проверку, если идут подряд два символа 0D0A, пишу в целевой файл только 0A. Но такое не работает. В итоге получается точная копия исходного файла. Использовал функции getc() и putc(). Посмотрел, что записывается в считываемый символ. Оказалось, что туда никогда не записывается символ 0D, только 0A. Поэтому и не работает проверка. Но в целевой файл-то пишется правильно и 0D и 0A. Как прочитать символ 0D? Вот кусок, который читает их исходного файла:
Непонятно как в переменную ch пишется сразу два байта, т.к. при записы в файл оба байта там есть (0D0A). |
| Автор: math64 17.4.2013, 10:20 | ||
| Ты в какой операционке это делаешь? В Линуксе твоя программа будет работать правильно. А вот в Windows по умолчанию при чтении 0D-0A ("\r\n") будет заменяться на 0A ('\n'), а при записи - 0A в автомате заменится 0D-0A. Чтобы этого не было, файл нужно откывать в двоичном режиме:
|
| Автор: ddsoft 17.4.2013, 21:29 | ||
Я делаю в Windows. Действительно, в линуксе работает как надо. Это особенность операционки при работе с текстовыми файлами? А как-нибудь можно, при работе с текстовыми файлами, указать в Windows, что не надо заменять при чтении 0D-0A на 0A? Да, при открытии в двоичном режиме всё работает. Спасибо! |
| Автор: ddsoft 17.4.2013, 23:09 | ||||||||||
Привожу код, преобразующий символы конца срок из Windows формата в Linux формат:
А как посоветуете сделать эффективнее?
Обнаружить символ 0D не получилось при открытии файла в текстовом режиме. А когда я поменял строки
на строки
всё заработало как надо. Мне такой код писал сразу два байта (\r\n) в файл, открытый в текстовом режиме.
А такой код у меня совсем не выполнялся. |
| Автор: volatile 18.4.2013, 00:18 |
| можно логику упростить. просто игнорировать 0xd, и все. |
| Автор: feodorv 18.4.2013, 04:34 | ||
Читайте, например, по 4 килобайта, выбрасывайте из буфера '\r' (длина буфера уменьшится), записывайте получившийся буфер...
Ну, с этим уже разобрались |
| Автор: ddsoft 18.4.2013, 06:50 | ||
Что вы имеете ввиду? Можно поподробнее, пожалуйста? Добавлено @ 06:55
А что будет, если длина буфера окажется больше оставшегося куска файла? Автоматически буфер будет подгоняться под размер оствшегося куска файла или целевой файл окажется длиннее исходного на длину остатка буфера? |
| Автор: feodorv 18.4.2013, 08:25 | ||||
Не понял, как это... Договорились же открывать файлы в бинарной моде, там чтение 1 в 1... Вот скелет алгоритма:
|
| Автор: math64 18.4.2013, 09:05 |
| Ну можно открыть файл в текстовом режиме, прочитать всё, и записать двоичном. Но так можно только в Windows, в Linux получите на выходе копию входного файла, поскольку там текстовый и двоичный режим не отличаются. При чтении же в текстовом режиме режиме 0D не игнорируется 0D 0A и 0A 0D (стандарт MAC) заменяются на 0A. Одиночный 0D нужно либо оставлять так, либо заменять на 0A (есть ОС, в которых для разделения строк использется 0D) |
| Автор: xvr 18.4.2013, 10:10 | ||||
Как правильно заметил math64 код можно несколько упростить:
|
| Автор: ddsoft 18.4.2013, 16:28 | ||||
Я имел ввиду, что если буфер 4 килобайта, а файл 10 килобайт, то при двукратной записи буфера в файл, весь файл ещё не перепишется, а при трёхкратной целевой файл окажется уже 12 килобайт вместо 10 килобайт. По вашему коду теперь понял, что записываться будет только количество реально прочитанных байт.
Я об этом не подумал. Спасибо за наводку Спасибо! |
| Автор: volatile 18.4.2013, 23:31 | ||
При преобравании виндозных файлов можно просто игнорировать. Если -же пишецца универсальный конвертер текстовых файлов любых операционок, то ни одна программа приведенная здесь работать правильно все равно не будет. |
| Автор: ddsoft 19.4.2013, 11:19 | ||
Допилил программу. Программа работает в windows и linux, преобразовывает концы строк win->unix и unix->win, имеет 3 входных параметра: 1) режим преобразования (win->unix или unix->win); 2) исходный файл; 3) целевой файл. Как на ваш взгляд можно сделать оптимальнее? Вот что у меня получилось:
|
| Автор: xvr 19.4.2013, 12:11 |
Можно, причем существенно оптимальнее. И вам тут уже говорили как именно |
| Автор: ddsoft 19.4.2013, 12:36 | ||
Да, но программа должна работать и в windows, и в linux. А оптимизация касалась только работы в windows. Вышеописанный трюк, основанный на особенности windows читать и писать конец строки, в linux не проходит. |
| Автор: math64 19.4.2013, 22:04 |
| stdio уже включает в себя буферизацию - так что явная буферизация не обязательно будет оптимальнее. А вот вызывать strcmp внутри цикла для проверки режима - явно не оптимально. Режим обычно задаётся краткая форма -u -w полная форма --unix-to-windows --windows-to-unix. Далее запоминается в булевскую или int переменную и либо вызываются разные функции для разных режимов либо проверяется эта переменная. |
| Автор: volatile 20.4.2013, 00:01 |
| Буферизацию надо попробовать сделать, если требуецца оптимизация, конечно. Стандартная буферизация хоть и есть, но почему-то очень медленная. Проверялось правда давно в старой студии, может в новых получче уже стало, не знаю. С простым буфером размером 16К, чтение/запись fread, fwrite работало раз в 100 быстрее чем через putc; |