用C向后读取文本文件 [英] Reading a text file backwards in C

查看:149
本文介绍了用C向后读取文本文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是用C向后读取文件的最好方法?我知道一开始你可能会认为这是没有任何用,但大多数日志等,在文件的最后追加的最新数据。我想从文件中的文本向后阅读,这将缓冲行 - 这是

What's the best way to read a file backwards in C? I know at first you may be thinking that this is no use whatsoever, but most logs etc. append the most recent data at the end of the file. I want to read in text from the file backwards, buffering it into lines - that is

ABC结果
高清结果
GHI

abc
def
ghi

应该读 GHI DEF ABC 中的行。

到目前为止,我曾尝试:

So far I have tried:

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

    void read_file(FILE *fileptr)
    {
        char currentchar = '\0';
        int size = 0;

        while( currentchar != '\n' )
        {
            currentchar = fgetc(fileptr); printf("%c\n", currentchar);
            fseek(fileptr, -2, SEEK_CUR);
            if( currentchar == '\n') { fseek(fileptr, -2, SEEK_CUR); break; }
            else size++;

        }
        char buffer[size]; fread(buffer, 1, size, fileptr);
        printf("Length: %d chars\n", size);
        printf("Buffer: %s\n", buffer);


    }


    int main(int argc, char *argv[])
    {
        if( argc < 2) { printf("Usage: backwards [filename]\n"); return 1; }

        FILE *fileptr = fopen(argv[1], "rb");
        if( fileptr == NULL ) { perror("Error:"); return 1; }

        fseek(fileptr, -1, SEEK_END); /* Seek to END of the file just before EOF */
        read_file(fileptr);


        return 0;


    }

在试图简单地读取一行和缓冲它。对不起,我的code是可怕的,我得到这样很困惑。我知道,你通常会为整个文件分配内存,然后在数据的读取,但对于大文件不断变化我认为这将是更好的直接读取(尤其是如果我想在一个文件中搜索文本)。

In an attempt to simply read one line and buffer it. Sorry that my code is terrible, I am getting so very confused. I know that you would normally allocate memory for the whole file and then read in the data, but for large files that constantly change I thought it would be better to read directly (especially if I want to search for text in a file).

在此先感谢

*对不起,忘了提,这将在Linux上使用,所以换行只是NL没有CR。 *

推荐答案

我推荐一个更便携(希望)文件的大小决定的方式,因为 fseek的(binaryStream,偏移,SEEK_END)不能保证正常工作。请参阅下面的code。

I recommend a more portable (hopefully) way of file size determination since fseek(binaryStream, offset, SEEK_END) is not guaranteed to work. See the code below.

我相信,文件应该在内核级别至少最低限度缓冲(例如缓冲每个默认文件至少一个块),所以寻求不应承担的额外的I / O显著量应该只在内部推进的文件位置。如果默认缓冲不满意,您可以尝试使用 setvbuf用来()来加快I / O。

I believe that files should be at least minimally buffered at the kernel level (e.g. buffering at least one block per file by default), so seeks should not incur significant amount of extra I/O and should only advance the file position internally. If the default buffering is not satisfactory, you may try to use setvbuf() to speed up the I/O.

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

/* File must be open with 'b' in the mode parameter to fopen() */
long fsize(FILE* binaryStream)
{
  long ofs, ofs2;
  int result;

  if (fseek(binaryStream, 0, SEEK_SET) != 0 ||
      fgetc(binaryStream) == EOF)
    return 0;

  ofs = 1;

  while ((result = fseek(binaryStream, ofs, SEEK_SET)) == 0 &&
         (result = (fgetc(binaryStream) == EOF)) == 0 &&
         ofs <= LONG_MAX / 4 + 1)
    ofs *= 2;

  /* If the last seek failed, back up to the last successfully seekable offset */
  if (result != 0)
    ofs /= 2;

  for (ofs2 = ofs / 2; ofs2 != 0; ofs2 /= 2)
    if (fseek(binaryStream, ofs + ofs2, SEEK_SET) == 0 &&
        fgetc(binaryStream) != EOF)
      ofs += ofs2;

  /* Return -1 for files longer than LONG_MAX */
  if (ofs == LONG_MAX)
    return -1;

  return ofs + 1;
}

/* File must be open with 'b' in the mode parameter to fopen() */
/* Set file position to size of file before reading last line of file */
char* fgetsr(char* buf, int n, FILE* binaryStream)
{
  long fpos;
  int cpos;
  int first = 1;

  if (n <= 1 || (fpos = ftell(binaryStream)) == -1 || fpos == 0)
    return NULL;

  cpos = n - 1;
  buf[cpos] = '\0';

  for (;;)
  {
    int c;

    if (fseek(binaryStream, --fpos, SEEK_SET) != 0 ||
        (c = fgetc(binaryStream)) == EOF)
      return NULL;

    if (c == '\n' && first == 0) /* accept at most one '\n' */
      break;
    first = 0;

    if (c != '\r') /* ignore DOS/Windows '\r' */
    {
      unsigned char ch = c;
      if (cpos == 0)
      {
        memmove(buf + 1, buf, n - 2);
        ++cpos;
      }
      memcpy(buf + --cpos, &ch, 1);
    }

    if (fpos == 0)
    {
      fseek(binaryStream, 0, SEEK_SET);
      break;
    }
  }

  memmove(buf, buf + cpos, n - cpos);

  return buf;
}

int main(int argc, char* argv[])
{
  FILE* f;
  long sz;

  if (argc < 2)
  {
    printf("filename parameter required\n");
    return -1;
  }

  if ((f = fopen(argv[1], "rb")) == NULL)
  {
    printf("failed to open file \'%s\'\n", argv[1]);
    return -1;
  }

  sz = fsize(f);
//  printf("file size: %ld\n", sz);

  if (sz > 0)
  {
    char buf[256];
    fseek(f, sz, SEEK_SET);
    while (fgetsr(buf, sizeof(buf), f) != NULL)
      printf("%s", buf);
  }

  fclose(f);
  return 0;
}

我只带2个不同的编译器测试在Windows操作系统上。

I've only tested this on windows with 2 different compilers.

这篇关于用C向后读取文本文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆