читать файл назад (последняя строка первая) - PullRequest
6 голосов
/ 03 августа 2011

файл выглядит так:

abcd
EFGH
ijkl

Я хочу прочитать файл, используя C, чтобы он сначала прочитал последнюю строку:

ijkl
EFGH
abcd

Я не могу найти решение, которое не использует array для хранения. Пожалуйста, помогите.

edit0: Спасибо за ответы на все вопросы. Просто чтобы вы знали, я тот, кто создает этот файл. Итак, я могу создать его в обратном порядке? Это возможно?

Ответы [ 5 ]

9 голосов
/ 03 августа 2011

Это выглядит так:

  1. Искать до одного байта до конца файла, используя fseek. Нет гарантии, что в последней строке будет EOL, поэтому последний байт на самом деле не имеет значения.
  2. Считать один байт, используя fgetc.
  3. Если этот байт является EOL, то последняя строка - это одна пустая строка, и она у вас есть.
  4. Используйте fseek снова, чтобы перейти назад на два байта и проверить этот байт с помощью fgetc.
  5. Повторяйте выше, пока не найдете EOL. Если у вас есть EOL, указатель файла будет в начале следующей (от конца) строки.
  6. ...
  7. Прибыль.

По сути, вы продолжаете выполнять (4) и (5), отслеживая, где вы были, когда нашли начало строки, чтобы вы могли вернуться туда до начала сканирования для начала следующей строки.

Пока вы открываете файл в текстовом режиме, вам не нужно беспокоиться о многобайтовых EOL в Windows (спасибо за напоминание, мистер Лутц).

Если вам дают ввод без поиска (например, канал), то вам не повезет, если вы сначала не захотите сбросить данные во временный файл.

Так что вы можете сделать это, но это довольно уродливо.

Вы можете сделать почти то же самое, используя mmap и указатель, если у вас есть mmap и «файл», с которым вы работаете, сопоставим. Техника была бы почти такой же: начинайте с конца и возвращайтесь назад, чтобы найти конец предыдущей строки.


Re: «Я тот, кто создает этот файл. Итак, могу ли я создать его в обратном порядке? Возможно ли это?»

Вы столкнетесь с такими же проблемами, но они будут хуже. Файлы в C являются по своей сути последовательными списками байтов, которые начинаются в начале и идут до конца; ты пытаешься работать против этого фундаментального свойства, а идти против основ никогда не бывает весело.

Вам действительно нужны ваши данные в виде простого текстового файла? Может быть, вам нужен текст / обычный текст в качестве окончательного результата, но все время до конца? Вы можете хранить данные в индексированном двоичном файле (возможно, даже в базе данных SQLite), и тогда вам нужно будет только беспокоиться о сохранении (или оконном) индекса в памяти, и это вряд ли будет проблемой (и если это так, используйте «реальная» база данных); затем, когда у вас есть все ваши строки, просто поменяйте местами указатель и начинайте.

3 голосов
/ 03 августа 2011

В псевдокоде:

open input file
while (fgets () != NULL)
{
   push line to stack
}
open output file
while (stack no empty)
{
   pop stack
   write popped line to file
}

Вышеприведенное эффективно, нет поиска (медленная операция) и файл читается последовательно.Однако есть два подводных камня к вышесказанному.

Первый - это fgets вызов.Буфер, предоставленный для fgets, может быть недостаточно большим, чтобы вместить целую строку из ввода, и в этом случае вы можете выполнить одно из следующих действий: снова прочитать и объединить;нажмите частичную строку и добавьте логику ко второй половине, чтобы исправить частичные строки или оберните строку в связанный список, и нажмите только связанный список, когда встретите новую строку / eof.Этот файл больше доступного ОЗУ для хранения стека, и в этом случае вам нужно будет записать структуру стека во временный файл всякий раз, когда он достигает некоторого порогового значения использования памяти.

1 голос
/ 10 июля 2016

Следующий код должен выполнить необходимую инверсию:

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

int main(int argc, char *argv[])
{
        FILE *fd;
        char len[400];
        int i;

        char *filename = argv[1];
        int ch;
        int count;

        fd = fopen(filename, "r");
        fseek(fd, 0, SEEK_END);
        while (ftell(fd) > 1 ){
                fseek(fd, -2, SEEK_CUR);
                if(ftell(fd) <= 2)
                        break;
                ch =fgetc(fd);
                count = 0;
                while(ch != '\n'){
                        len[count++] = ch;
                        if(ftell(fd) < 2)
                                break;
                        fseek(fd, -2, SEEK_CUR);
                        ch =fgetc(fd);
                }
                for (i =count -1 ; i >= 0 && count > 0  ; i--)
                        printf("%c", len[i]);
                printf("\n");
        }
        fclose(fd);
}
0 голосов
/ 17 марта 2017

Может быть, это делает трюк, Он полностью изменяет содержимое файла, как строку

  1. Определите переменную типа string с размером вашего файла
  2. Получить содержимоефайла и сохраните в переменной
  3. Используйте strrev (), чтобы перевернуть строку.

Позже вы можете отобразить вывод или даже записать его в файл.Код выглядит так:

#include <stdio.h>
#include <String.h>

int main(){
    FILE *file;
    char all[1000];

    // give any name to read in reverse order
    file = fopen("anyFile.txt","r");

    // gets all the content and stores in variable all
    fscanf(file,"%[]",all);

    // Content of the file 
    printf("Content Of the file %s",all);

    // reverse the string 
    printf("%s",strrev(all));
    fclose(file);
    return 0;
}
0 голосов
/ 01 мая 2014

Следующее работает для меня в Linux, где разделитель строк текстового файла - "\ n".

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

void readfileinreverse(FILE *fp)
{
    int i, size, start, loop, counter;
    char *buffer;
    char line[256];
    start = 0;
    fseek(fp, 0, SEEK_END);
    size = ftell(fp);

    buffer = malloc((size+1) * sizeof(char));

    for (i=0; i< size; i++)
    {
        fseek(fp, size-1-i, SEEK_SET);
        buffer[i] = fgetc(fp);

        if(buffer[i] == 10)
        {
           if(i != 0)
           {
            counter = 0;        
            for(loop = i; loop > start; loop--)
            {
                if((counter == 0) && (buffer[loop] == 10))
                {
                    continue;
                }               
                line[counter] = buffer[loop];
                counter++;
            }
            line[counter] = 0;
            start = i;
            printf("%s\n",line);
           }
        }
    }

    if(i > start)
    {    
        counter = 0;
        for(loop = i; loop > start; loop--)
        {       
            if((counter == 0) && ((buffer[loop] == 10) || (buffer[loop] == 0)))
            {
                continue;
            }               
            line[counter] = buffer[loop];
            counter++;
        }
        line[counter] = 0;
        printf("%s\n",line);

        return;
    }
}

int main()
{
    FILE *fp = fopen("./1.txt","r");
    readfileinreverse(fp);
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...