Как читать по одному байту за раз из массива? - PullRequest
0 голосов
/ 18 апреля 2011

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

Пример:

while  (x = fgetc(file) != EOF )
{
    count++;//Counts the number of bytes
}

chars = (unsigned char*) malloc (sizeof(unsigned char)*count+1);
rewind(file);

FILE* output_file = fopen("Filename.jpg", "rb");

while(chars[i] != specificByte)
{
    fwrite(?,?,?,?); 
}

Это не тот код, который я использую, но я просто хотел выложить что-то, чтобы показать, где у меня проблема.

Возможно, было бы лучше просто читать прямо из файла, а не помещать байты в массив?

Ответы [ 5 ]

2 голосов
/ 18 апреля 2011

Вот один полный пример с fread / fwrite.

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

Я даже не уверен, что это более эффективно, чем использование fgetc & fputc, но по крайней мере файлы читаются и записываются в один вызов функции .

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

/* this function retrieves the size of the input file */
long get_filesize(FILE *fp)
{
    long filesize;

    fseek(fp, 0, SEEK_END);
    filesize = ftell(fp);
    rewind(fp);

    return filesize;
}

int main(void)
{
    FILE *fp;
    unsigned char *data;
    long filesize;
    unsigned char specificByte = 10; /* line feed for example */

    /* open the input file */
    fp = fopen("input_file", "rb");
    if(fp == NULL) exit(EXIT_FAILURE);

    /* get the filesize */
    filesize = get_filesize(fp);

    /* allocate space for the file */
    data = malloc(filesize * sizeof(unsigned char));
    if(data == NULL) exit(EXIT_FAILURE);

    /* read the file into memory */
    fread(data, filesize, sizeof(unsigned int), fp);
    fclose(fp);

    /* open output file */
    fp = fopen("output_file", "wb");
    if(fp == NULL) {
        free(data);
        exit(EXIT_FAILURE);
    }

    /* check how many bytes should be written into output file */
    int i;
    for(i = 0; i < filesize && data[i] != specificByte; ++i);

    /* write the bytes */
    fwrite(data, i, sizeof(unsigned char), fp);

    /* close the file and free the memory */    
    fclose(fp);
    free(data);

    return EXIT_SUCCESS;
}
2 голосов
/ 18 апреля 2011

Если я могу сделать предложение, вероятно, было бы намного эффективнее читать массив, пока вы не найдете свой стоп-байт, а затем записать массив от начала до этого стоп-байта за один ввод / вывод.

1 голос
/ 18 апреля 2011

Простой, но эффективный способ сделать это - вообще избежать чтения в память и просто сделать следующее:

while ((input_char = fgetc(input_fp)) != EOF)
{
    if (input_char != specificByte)
    {
        fputc(input_char, output_fp);
    }
    else
    {
        /* do something with input_char */
    }
}

Это теоретически неэффективно, поскольку вы читаете один символ за разиз буфера, который может быть дорогостоящим.Тем не менее, для многих приложений это будет работать просто отлично, тем более что чтение файлов буферизируется стандартной библиотекой C.

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

/* Don't loop through the chars just to find out the file size. Instead, use
 * stat() to find out the file size and allocate that many bytes into array.
 */
char* array = (char*) malloc(file_size);
fread(array, sizeof(char), file_size, input_fp);

/* iterate through the file buffer until you find the byte you're looking for */
for (char* ptr = array; ptr < array + file_size; ptr++);
{
    if (*ptr == specificByte)
    {
        break;
    }
}

/* Write everything up to ptr into the output file */
fwrite(array, sizeof(char), ptr - array, output_fp);

/* ptr now points to the byte you're looking for. Manipulate as desired */
0 голосов
/ 18 апреля 2011

Если вам не нужно читать весь файл за раз, просто выделите буфер фиксированного размера и вообще избегайте malloc; не связывайтесь с динамическим управлением памятью, если у вас нет , чтобы связываться с динамическим управлением памятью.

#define PAGE_SIZE ... // however big a chunk you process at a time
...
unsigned char inbuf[PAGE_SIZE];
unsigned char outbuf[PAGE_SIZE];

FILE *input_stream = fopen(...);
FILE *output_stream = fopen(...);

while (fread(inbuf, sizeof inbuf, 1, input_stream))
{
  unsigned char *r = inbuf, *w = outbuf;
  while (r != inbuf + sizeof inbuf && *r != specificByte)
    *w++ = *r++;
  fwrite(outbuf, (size_t) (w - outbuf), 1, output_stream);
  if (*r == specific_byte)
    break;
}
0 голосов
/ 18 апреля 2011

Вот один из способов:

int putResult = 0;

for(int i = 0 ; i < BUFFER_SIZE && buffer[i] != specificByte && putResult != EOF ; ++i)
{
    putResult = fputc(buffer[i]);
}
if (putResult == EOF)
{
    // Deal with the error (in errno)
}

Условие for выходит из цикла, если

  • i попадает в конец буфера
  • конкретный байт находится в буфере
  • fputc() возвращает ошибку.
...