Try file
, then file -k
, then dos2unix -ih
file
will usually be enough. But for tough cases try file -k
or dosunix -ih
.
Details below.
Try file -k
Short version: file -k somefile.txt
will tell you.
- It will output
with CRLF line endings
for DOS/Windows line endings. - It will output
with CR line endings
for MAC line endings. - It will just output
text
for Linux/Unix “LF” line endings. (So if it does not explicitly mention any kind ofline endings
then this means: “LF line endings”.)
Long version see below.
Real world example: Certificate Encoding
I sometimes have to check this for PEM certificate files.
The trouble with regular file
is this: Sometimes it’s trying to be too smart/too specific.
Let’s try a little quiz: I’ve got some files. And one of these files has different line endings. Which one?
(By the way: this is what one of my typical “certificate work” directories looks like.)
Let’s try regular file
:
$ file -- *
0.example.end.cer: PEM certificate
0.example.end.key: PEM RSA private key
1.example.int.cer: PEM certificate
2.example.root.cer: PEM certificate
example.opensslconfig.ini: ASCII text
example.req: PEM certificate request
Huh. It’s not telling me the line endings. And I already knew that those were cert files. I didn’t need “file” to tell me that.
Some network appliances are really, really picky about how their certificate files are encoded. That’s why I need to know.
What else can you try?
You might try dos2unix
with the --info
switch like this:
$ dos2unix --info -- *
37 0 0 no_bom text 0.example.end.cer
0 27 0 no_bom text 0.example.end.key
0 28 0 no_bom text 1.example.int.cer
0 25 0 no_bom text 2.example.root.cer
0 35 0 no_bom text example.opensslconfig.ini
0 19 0 no_bom text example.req
So that tells you that: yup, “0.example.end.cer” must be the odd man out. But what kind of line endings are there? Do you know the dos2unix output format by heart? (I don’t.)
But fortunately there’s the --keep-going
(or -k
for short) option in file
:
$ file --keep-going -- *
0.example.end.cer: PEM certificate12- , ASCII text, with CRLF line terminators12- data
0.example.end.key: PEM RSA private key12- , ASCII text12- data
1.example.int.cer: PEM certificate12- , ASCII text12- data
2.example.root.cer: PEM certificate12- , ASCII text12- data
example.opensslconfig.ini: ASCII text12- data
example.req: PEM certificate request12- , ASCII text12- data
Excellent! Now we know that our odd file has DOS (CRLF
) line endings. (And the other files have Unix (LF
) line endings. This is not explicit in this output. It’s implicit. It’s just the way file
expects a “regular” text file to be.)
(If you wanna share my mnemonic: “L” is for “Linux” and for “LF”.)
Now let’s convert the culprit and try again:
$ dos2unix -- 0.example.end.cer
$ file --keep-going -- *
0.example.end.cer: PEM certificate12- , ASCII text12- data
0.example.end.key: PEM RSA private key12- , ASCII text12- data
1.example.int.cer: PEM certificate12- , ASCII text12- data
2.example.root.cer: PEM certificate12- , ASCII text12- data
example.opensslconfig.ini: ASCII text12- data
example.req: PEM certificate request12- , ASCII text12- data
Good. Now all certs have Unix line endings.
Try dos2unix -ih
I didn’t know this when I was writing the example above but:
Actually it turns out that dos2unix will give you a header line if you use -ih
(short for --info=h
) like so:
$ dos2unix -ih -- *
DOS UNIX MAC BOM TXTBIN FILE
0 37 0 no_bom text 0.example.end.cer
0 27 0 no_bom text 0.example.end.key
0 28 0 no_bom text 1.example.int.cer
0 25 0 no_bom text 2.example.root.cer
0 35 0 no_bom text example.opensslconfig.ini
0 19 0 no_bom text example.req
And another “actually” moment: The header format is really easy to remember: Here’s two mnemonics:
- It’s DUMB (left to right: d for Dos, u for Unix, m for Mac, b for BOM).
- And also: “DUM” is just the alphabetical ordering of D, U and M.
Further reading
man file
man dos2unix
- Wikipedia: Newline
Решил прочесть из текстового файла матрицу и определить количество строк и столбцов.
Исхожу из соображений, что данные, записанные в текстовый файл, представляют собой некий одномерный массив, разделенный символами конца строк ‘n’.
Построчный анализ в окне Debug показывает, что реализованный код читает все символы, а символ конца строки пропускает, перескакивая на следующую строку.
Никак не могу понять где ошибка. Помогите!
#include <fstream>
#include <iostream>
using namespace::std;
int main(){
int i = 0; // индекс элементов строки ФАЙЛА
int row_size = 0; // количество строк матрицы
int column_size = 0; // количество столбцов матрицы
char* buffer; // указатель на адрес, по которому должны временно размещаться числа, полученные из строки файла
ifstream input_data("The_Matrix.txt");
if(!input_data.is_open()){
cout << "Cant open file" << endl;
}else{
while(input_data>>buffer){
if(*buffer=='n'){
column_size=i;
i = 0;
row_size++;
}
i++;
}
}
cout << row_size << " ";
cout << column_size << endl;
input_data.close();
return 0;
}
Попробуйте “файл -k”
Я иногда должен проверить это для файлов сертификата PEM.
Проблема с обычным file
заключается в следующем: иногда он пытается быть слишком умным/слишком конкретным.
Давайте попробуем небольшой тест: у меня есть несколько файлов. И один из этих файлов имеет разные окончания строки. Который из?
(Кстати: вот так выглядит один из моих типичных каталогов “работы с сертификатами”.)
Давайте попробуем обычный file
:
$ file -- *
0.example.end.cer: PEM certificate
0.example.end.key: PEM RSA private key
1.example.int.cer: PEM certificate
2.example.root.cer: PEM certificate
example.opensslconfig.ini: ASCII text
example.req: PEM certificate request
Да. Это не говорит мне об окончании строки. И я уже знал, что это сертификаты. Мне не нужно было “файл”, чтобы сказать мне это.
Что еще можно попробовать?
Вы можете попробовать dos2unix
с переключателем --info
следующим образом:
$ dos2unix --info -- *
37 0 0 no_bom text 0.example.end.cer
0 27 0 no_bom text 0.example.end.key
0 28 0 no_bom text 1.example.int.cer
0 25 0 no_bom text 2.example.root.cer
0 35 0 no_bom text example.opensslconfig.ini
0 19 0 no_bom text example.req
Это говорит о том, что: yup, “0.example.end.cer” должно быть нечетным человеком. Но что за концы строк? Вы знаете формат вывода dos2unix наизусть? (Я не.)
Но, к счастью, там --keep-going
(или -k
для краткости) вариант в file
:
$ file --keep-going -- *
0.example.end.cer: PEM certificate12- , ASCII text, with CRLF line terminators12- data
0.example.end.key: PEM RSA private key12- , ASCII text12- data
1.example.int.cer: PEM certificate12- , ASCII text12- data
2.example.root.cer: PEM certificate12- , ASCII text12- data
example.opensslconfig.ini: ASCII text12- data
example.req: PEM certificate request12- , ASCII text12- data
Отлично! Теперь мы знаем, что наш нечетный файл имеет окончания строки DOS (CRLF
). (И другие файлы имеют окончания строки Unix (LF
). Это не явно в этом выводе. Это неявное. Это просто способ, которым file
ожидает, что “обычный” текстовый файл будет.)
(Если вы хотите поделиться моей мнемоникой: “L” для “Linux” и “LF”.)
Теперь давайте преобразуем преступника и попробуйте снова:
$ dos2unix -- 0.example.end.cer
$ file --keep-going -- *
0.example.end.cer: PEM certificate12- , ASCII text12- data
0.example.end.key: PEM RSA private key12- , ASCII text12- data
1.example.int.cer: PEM certificate12- , ASCII text12- data
2.example.root.cer: PEM certificate12- , ASCII text12- data
example.opensslconfig.ini: ASCII text12- data
example.req: PEM certificate request12- , ASCII text12- data
Хорошо. Теперь все сертификаты имеют окончания Unix.
дальнейшее чтение
-
man file
-
man dos2unix
- Википедия: Новая строка
Язык программирования Си поддерживает множество функций стандартных библиотек для файлового ввода и вывода. Эти функции составляют основу заголовочного файла стандартной библиотеки языка Си <stdio.h>
.
Функциональность ввода-вывода языка Си по текущим стандартам реализуется на низком уровне. Язык Си абстрагирует все файловые операции, превращая их в операции с потоками байтов, которые могут быть как «потоками ввода», так и «потоками вывода». В отличие от некоторых ранних языков программирования, язык Си не имеет прямой поддержки произвольного доступа к файлам данных; чтобы считать записанную информацию в середине файла, программисту приходится создавать поток, ищущий в середине файла, а затем последовательно считывать байты из потока.
Потоковая модель файлового ввода-вывода была популяризирована во многом благодаря операционной системе Unix, написанной на языке Си. Большая функциональность современных операционных систем унаследовала потоки от Unix, а многие языки семейства языков программирования Си унаследовали интерфейс файлового ввода-вывода языка Си с небольшими отличиями (например, PHP). Стандартная библиотека C++ отражает потоковую концепцию в своём синтаксисе (смотрите iostream).
Открытие файла при помощи функции fopen[править | править код]
Файл открывается при помощи функции fopen
, которая возвращает информацию потока ввода-вывода, прикреплённого к указанному файлу или другому устройству, с которого идет чтение (или в который идет запись). В случае неудачи функция возвращает нулевой указатель.
Схожая функция freopen
библиотеки Си выполняет аналогичную операцию после первого закрытия любого открытого потока, связанного с её параметрами.
Они объявляются как
FILE *fopen(const char *path, const char *mode); FILE *freopen(const char *path, const char *mode, FILE *fp);
Функция fopen
по сути представляет собой «обертку» более высокого уровня системного вызова open
операционной системы Unix. Аналогично, fclose
является оберткой системного вызова Unix close
, а сама структура FILE
языка Си зачастую обращается к соответствующему файловому дескриптору Unix. В POSIX-окружении функция fdopen
может использоваться для инициализации структуры FILE
файловым дескриптором. Тем не менее, файловые дескрипторы как исключительно Unix-концепция не представлены в стандарте языка Си.
Параметр mode
(режим) для fopen
и freopen
должен быть строковый и начинаться с одной из следующих последовательностей:
режим | описание | начинает с.. | ||
---|---|---|---|---|
r | rb | открывает для чтения | начала | |
w | wb | открывает для записи (создаёт файл в случае его отсутствия). Удаляет содержимое и перезаписывает файл. | начала | |
a | ab | открывает для добавления (создаёт файл в случае его отсутствия) | конца | |
r+ | rb+ | r+b | открывает для чтения и записи | начала |
w+ | wb+ | w+b | открывает для чтения и записи. Удаляет содержимое и перезаписывает файл. | начала |
a+ | ab+ | a+b | открывает для чтения и записи (создаёт файл в случае его отсутствия) | конца |
Значение «b» зарезервировано для двоичного режима С. Стандарт языка Си описывает два вида файлов — текстовые и двоичные — хотя операционная система не требует их различать (однако, для некоторых компиляторов, например LCC, указание ‘b’ при работе с бинарным файлом принципиально важно!). Текстовый файл — файл, содержащий текст, разбитый на строки при помощи некоторого разделяющего символа окончания строки или последовательности (в Unix — одиночный символ перевода строкиn
; в Microsoft Windows за символом перевода строки следует знак возврата каретки)rn
. При считывании байтов из текстового файла, символы конца строки обычно связываются (заменяются) с переводом строки для упрощения обработки. При записи текстового файла одиночный символ перевода строки перед записью связывается (заменяется) с специфичной для ОС последовательностью символов конца строки. Двоичный файл — файл, из которого байты считываются и выводятся в «сыром» виде без какого-либо связывания (подстановки).
При открытом файле в режиме обновления (‘+’ в качестве второго или третьего символа аргумента обозначения режима) и ввод и вывод могут выполняться в одном потоке. Тем не менее, запись не может следовать за чтением без промежуточного вызова fflush
или функции позиционирования в файле (fseek
, fsetpos
или rewind
), а чтение не может следовать за записью без промежуточного вызова функции позиционирования в файле. [1]
Режимы записи и добавления пытаются создать файл с заданным именем, если такого файла ещё не существует. Как указывалось выше, если эта операция оканчивается неудачей, fopen
возвращает NULL
.
Закрытие потока при помощи fclose[править | править код]
Функция fclose
принимает один аргумент: указатель на структуру FILE
потока для закрытия.
Функция возвращает нуль в случае успеха и EOF в случае неудачи.
При нормальном завершении программы функция вызывается автоматически для каждого открытого файла.
Чтение из потока[править | править код]
при помощи fgetc[править | править код]
Функция fgetc
применяется для чтения символа из потока.
В случае успеха fgetc
возвращает следующий байт или символ из потока (зависит от того, файл «двоичный» или «текстовый», как выше обсуждалось). В противном случае fgetc
возвращает EOF
. (Отдельный тип ошибок можно определить вызовом ferror
или feof
с указателем на файл.)
Стандартный макрос getc
так же определён в <stdio.h>
, успешно работая как fgetc
, кроме одного: будучи макросом, он может обрабатывать свои аргументы более одного раза.
Стандартная функция getchar
так же определена в <stdio.h>
, она не принимает аргументов и эквивалентна getc(stdin)
.
«Ловушка» EOF[править | править код]
Распространённой ошибкой является использование fgetc
, getc
или getchar
для присваивания результата переменной типа char
перед сравнением его с EOF
. Следующий фрагмент кода демонстрирует эту ошибку, а рядом приведён корректный вариант:
Ошибка | Правильно |
---|---|
char c; while ((c = getchar()) != EOF) { putchar(c); } |
int c; while ((c = getchar()) != EOF) { putchar(c); } |
Нужно учитывать систему, в которой тип char
, длина которого составляет 8 бит (в частности, архитектура x86), представляет 256 различных значений. getchar
может возвращать любой из 256 возможных символов, а также может возвращать EOF
для обозначения конца файла, значение которого не может совпадать ни с одним из значений char
.
Когда результат getchar
присваивается переменной типа char
, которая может представить лишь 256 различных значений, происходит вынужденная потеря информации — при сжатии 257 значений в 256 «мест» происходит коллизия. Значение EOF
при конвертации в char
становится неотличимым от любого из остальных 256 символов. Если этот символ обнаружен в файле, код, приведённый выше, может принять его за признак конца файла, или, что ещё хуже, если тип char
— беззнаковый, тогда с учётом того, что EOF
— значение отрицательное, оно никогда не сможет стать равным любому беззнаковому char
, и таким образом, пример выше не закончится на метке конца файла, а будет выполняться вечно, повторно печатая символ, получающийся при конвертации EOF
в char
.
В системах, где int
и char
одинакового размера[каких?][источник не указан 4518 дней], даже «правильный» вариант будет работать некорректно из-за сходства EOF
и другого символа. Правильным вариантом обработки подобной ситуации является проверка feof
и ferror
после того, как getchar
вернет EOF
. Если feof
определит, что конец файла ещё не достигнут, а ferror
«сообщит», что ошибок нет, то EOF
, возвращённый getchar
, может считаться текущим символом. Такие дополнительные проверки делаются редко, так как большинство программистов считает, что их код никогда не будет выполняться на подобных системах с «большим char
». Другой способ состоит в использовании проверки при компиляции, что UINT_MAX > UCHAR_MAX
, которая хотя бы предотвратит компиляцию на подобных системах.[источник не указан 55 дней]
при помощи fgets[править | править код]
Функция fgets
применяется для чтения строки из потока. Считывание происходит до тех пор пока не будет достигнут конец строки (hex:0D0A, эквивалентны в листингах n) или длина строки, в которую происходит считывание.
Предположим, у нас есть файл some_file.txt с текстом
палиндромы А в Енисее - синева. А лама мала. А лис, он умен - крыса сыр к нему носила. (И. Бабицкий)
#include <stdio.h> #include <string.h> int main (int argc, char* argv[]) /* argc хранит количество параметров, а argv[] указатели на эти параметры. Например, если мы запустим исполняемый файл "fgets_example param1 param2", то argc будет равно 3, а argv[] = {"fgets_example", "param1", "param2"}*/ { FILE *file; char *fname = "some_file.txt"; char result_string[20]; //Строка в 20 символов file = fopen(fname,"r"); if(file == NULL) { printf("не могу открыть файл '%s'",fname); return 0; } int i=0; char *real_tail; while(fgets(result_string,sizeof(result_string),file)) { real_tail=""; printf("Строка %d:Длина строки - %d:",i++,strlen(result_string)); if(result_string[strlen(result_string)-1] == 'n')//проверяем является ли последний элемент в строке символом её окончания { real_tail="\n"; result_string[strlen(result_string)-1]=''; };// эта часть кода добавлена лишь для отображения символа конца строки в консоль без перевода на новую строку printf("%s%sn",result_string,real_tail); } fclose(file); return 0; }
в результате выполнения мы получим
Строка 0:Длина строки - 11:палиндромыn Строка 1:Длина строки - 19: А в Енисее - си Строка 2:Длина строки - 6:нева.n Строка 3:Длина строки - 17: А лама мала.n Строка 4:Длина строки - 19: А лис, он умен Строка 5:Длина строки - 19:- крыса сыр к нему Строка 6:Длина строки - 19:носила. (И. Бабицки Строка 7:Длина строки - 2:й)
Функция strlen определяет длину строки по количеству символов до ”, например:
printf("%d",strlen("123 123")); //выведет 4
fwrite[править | править код]
В языке программирования Си функции fread
и fwrite
соответственно реализуют файловые операции ввода и вывода. fread
и fwrite
объявлены в <stdio.h>
.
Запись в файл при помощи fwrite[править | править код]
fwrite определяется как
int fwrite ( const char * array, size_t size, size_t count, FILE * stream );
Функция fwrite
записывает блок данных в поток. Таким образом запишется массив элементов array
в текущую позицию в потоке. Для каждого элемента запишется size
байт. Индикатор позиции в потоке изменится на число байт, записанных успешно. Возвращаемое значение будет равно count
в случае успешного завершения записи. В случае ошибки возвращаемое значение будет меньше count
.
Следующая программа открывает файл пример.txt, записывает в него строку символов, а затем его закрывает.
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { FILE *fp; size_t count; char const *str = "приветn"; fp = fopen("пример.txt", "wb"); if(fp == NULL) { perror("ошибка открытия пример.txt"); return EXIT_FAILURE; } count = fwrite(str, sizeof(char), strlen(str), fp); printf("Записано %lu байт. fclose(fp) %s.n", (unsigned long)count, fclose(fp) == 0 ? "успешно" : "с ошибкой"); fclose(fp); return 0; }
Запись в поток при помощи fputс[править | править код]
Функция fputc
применяется для записи символа в поток.
int fputc(int c, FILE *fp);
Параметр c
«тихо» конвертируется в unsigned char
перед выводом. Если прошло успешно, то fputc
возвращает записанный символ. Если ошибка, то fputc
возвращает EOF
.
Стандартный макрос putc
также определён в <stdio.h>
, работая в общем случае аналогично fputc
, за исключением того момента, что будучи макросом, он может обрабатывать свои аргументы более одного раза.
Стандартная функция putchar
, также определённая в <stdio.h>
, принимает только первый аргумент, и является эквивалентной putc(c, stdout)
, где c
является упомянутым аргументом.
Пример использования[править | править код]
Нижеследующая программа на языке Си открывает двоичный файл с названием мойфайл, читает пять байт из него, а затем закрывает файл.
#include <stdio.h> #include <stdlib.h> int main(void) { char buffer[5] = {0}; /* инициализируем нулями */ int i, rc; FILE *fp = fopen("мойфайл", "rb"); if (fp == NULL) { perror("Ошибка при открытии "мойфайл""); return EXIT_FAILURE; } for (i = 0; (rc = getc(fp)) != EOF && i < 5; buffer[i++] = rc); fclose(fp); if (i == 5) { puts("Прочитанные байты..."); printf("%x %x %x %x %xn", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]); } else fputs("Ошибка чтения файла.n", stderr); return EXIT_SUCCESS; }
См. также[править | править код]
printf
Дополнительные источники[править | править код]
- stdio.h on Coding Programmer Page / C Library Reference and Examples (en)
fclose(3)
— страница справки man по библиотечным функциям GNU/Linux (англ.)fgetc(3)
— страница справки man по библиотечным функциям GNU/Linux (англ.)fopen(3)
— страница справки man по библиотечным функциям GNU/Linux (англ.)fputc(3)
— страница справки man по библиотечным функциям GNU/Linux (англ.)- Вопрос 12.1 в вопросах-ответах по Си: использование
char
для хранения возвращаемогоgetc
значения
Форум программистов Vingrad
Модераторы: Daevaorn |
Поиск: |
|
определить конец строки при чтении из файла, используя потоки |
Опции темы |
Flashdown |
|
||
Шустрый Профиль
Репутация: нет
|
как при чтении данных из файла с помощью fstream определить что строка кончилась, а ещё лучше – установить указатель на следующую строку? |
||
|
|||
mes |
|
||
любитель Профиль Репутация: 144
|
проверяй код символа. конец стоки это rn или n ——————– http://opendots.net |
||
|
|||
Flashdown |
|
||
Шустрый Профиль
Репутация: нет
|
если в цикле считывать данные в переменную типа char , то символ конца строки в неё не попадает… |
||
|
|||
mes |
|
||
любитель Профиль Репутация: 144
|
а файл открыт как? как бинарный? ——————– http://opendots.net |
||
|
|||
Flashdown |
|
||
Шустрый Профиль
Репутация: нет
|
как его не открывай, всё равно не читает конец строки! |
||
|
|||
Flashdown |
|
||
Шустрый Профиль
Репутация: нет
|
надо было просто |
||
|
|||
d06osipov |
|
||
Шустрый Профиль Репутация: нет
|
Считывать можно разными способами: т. о. код будет такой:
|
||
|
|||
|
Правила форума “С++:Общие вопросы” | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) |
0 Пользователей: |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |