Если вы действительно, действительно должны (ab) использовать fscanf()
при чтении файла, то здесь описывается, как вы могли бы это сделать:
- открыть файл
- используйте
fseek()
и ftell()
, чтобы найти размер файла rewind()
(или fseek(fp, 0, SEEK_SET)
) для сброса файла в начало - выделить большой буфер
- создать строку формата, которая считывает правильное количество байтов в буфер и записывает, сколько символов прочитано
- использовать формат с
fscanf()
- добавить нулевой завершающий байт в зарезервированное для него пространство
- распечатать содержимое файла в виде большой строки.
Если в файле нет нулевых байтов, вы увидите напечатанное содержимое файла.Если в файле есть нулевые байты, вы увидите содержимое файла вплоть до первого нулевого байта.
Я выбрал анодное имя data
для файла, который нужно прочитать - есть бесконечные способы, которыми вы можетесделайте это выбираемым во время выполнения.
Есть несколько предположений относительно размера файла (прежде всего, что размер не больше, чем может быть помещен в long
со знаком переполнения, и что он непусто).Он использует тот факт, что формат %c
может принимать длину, как и большинство форматов, и не добавляет нулевого терминатора в конце строки, которую он читает, и не суетится относительно того, являются ли символыread - нулевые байты или что-то еще - он просто читает их.Он также использует тот факт, что вы можете указать размер переменной для хранения смещения с помощью спецификации преобразования %n
(или, в данном случае, %ln
).И наконец, предполагается, что файл не сжимается (он будет игнорировать рост, если он растет) и что это файл с возможностью поиска, а не FIFO или какой-либо другой специальный тип файла, который не поддерживает поиск.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char filename[] = "data";
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
exit(EXIT_FAILURE);
}
fseek(fp, 0, SEEK_END);
long length = ftell(fp);
rewind(fp);
char *buffer = malloc(length + 1);
if (buffer == NULL)
{
fprintf(stderr, "Failed to allocate %ld bytes\n", length + 1);
exit(EXIT_FAILURE);
}
char format[32];
snprintf(format, sizeof(format), "%%%ldc%%ln", length);
long nbytes = 0;
if (fscanf(fp, format, buffer, &nbytes) != 1 || nbytes != length)
{
fprintf(stderr, "Failed to read %ld bytes (got %ld)\n", length, nbytes);
exit(EXIT_FAILURE);
}
buffer[length] = '\0';
printf("<<<SOF>>\n%s\n<<EOF>>\n", buffer);
free(buffer);
return(0);
}
Это все еще злоупотребление fscanf()
- было бы лучше использовать fread()
:
if (fread(buffer, sizeof(char), length, fp) != (size_t)length)
{
fprintf(stderr, "Failed to read %ld bytes\n", length);
exit(EXIT_FAILURE);
}
Затем можно опустить переменную format
и код, который ее устанавливает, итакже nbytes
.Или вы можете оставить nbytes
(возможно, как size_t
вместо long
) и присвоить ему результат fread()
, а также использовать значение в отчете об ошибках, аналогично тесту в fscanf()
Вариант.
Вы можете получить предупреждение от GCC о не буквальной строке формата для fscanf()
.Это правильно, но это не опасно, потому что программист полностью отвечает за содержимое строки формата.