文件看起来像这样:
abcd
efgh
ijkl
我想使用 C
读取文件,使其首先读取最后一行:
ijkl
efgh
abcd
我似乎找不到不使用 array
存储的解决方案。请帮忙。
编辑0: 感谢所有回答者。只是想让你们知道,我是创建这个文件的人。所以,我能否以相反的顺序创建它?这可行吗?
操作步骤如下:
fseek
函数将文件指针定位到文件末尾前一个字节。由于最后一行可能没有EOL(行尾符),因此最后一个字节并不重要。fgetc
函数读取一个字节。fseek
函数向后移动两个字节,并使用fgetc
函数检查该字节。基本上,您需要在执行第(4)和(5)个步骤时记录您找到行开头的位置,以便在开始扫描下一行之前回到那里。
只要以文本模式打开文件,您就不必担心Windows上的多字节EOL(感谢Mr. Lutz提醒)。
如果您收到不可寻址的输入(例如管道),那么您就没办法了,除非您想先将输入转储到临时文件中。
因此,您可以这样做,但它相当丑陋。
如果您有mmap
函数可用并且您正在处理的“文件”可映射,则可以使用mmap
和指针执行几乎相同的操作。技术基本相同:从末尾开始向后移动,以找到上一行的结尾。
回复:“我是创建这个文件的人。那么,我能以相反的顺序创建它吗?这是可能的吗?”
你会遇到同样类型的问题,但会更加严重。在 C 中,文件本质上是一个从开头到结尾的顺序字节列表;你正在努力反对这个基本属性,而违反基本原则从来都不是一件有趣的事情。
你真的需要把数据存储在纯文本文件中吗?也许最终输出需要使用 text/plain,但是否一直如此呢?你可以将数据存储在索引二进制文件中(甚至是 SQLite 数据库),然后只需担心保留(或分段)索引即可,这不太可能成为问题(如果确实存在问题,请使用“真正”的数据库);然后,当你有了所有的行时,只需反转索引即可。
fseek
是一个缓慢的操作,而你正在对文件中的每个字节执行它。 - Skizzmmap
。 - mu is too shortf*
IO 函数,当以文本(非二进制)模式打开 FILE *
时,会自动为您执行 EOL 转换。 - Chris Lutz伪代码中:
open input file
while (fgets () != NULL)
{
push line to stack
}
open output file
while (stack no empty)
{
pop stack
write popped line to file
}
#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);
}
以下代码适用于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;
}
malloc()
为buffer
分配内存,但在函数readfileinreverse()
结束时没有调用free(buffer)
释放内存。 - iamantony我知道这个问题已经得到了回答,但是被接受的回答没有包含代码片段,而其他片段则感觉过于复杂。 这是我的实现:
#include <stdio.h>
long file_size(FILE* f) {
fseek(f, 0, SEEK_END); // seek to end of file
long size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
return size;
}
int main(int argc, char* argv[]) {
FILE *in_file = fopen(argv[1], "r");
long in_file_size = file_size(in_file);
printf("Got file size: %ld\n", in_file_size);
// Start from end of file
fseek(in_file, -1, SEEK_END); // seek to end of file
for (int i = in_file_size; i > 0; i--) {
char current_char = fgetc(in_file); // This progresses the seek location
printf("Got char: |%c| with hex: |%x|\n", current_char, current_char);
fseek(in_file, -2, SEEK_CUR); // Go back 2 bytes (1 to compensate)
}
printf("Done\n");
fclose(in_file);
}
也许,这就是诀窍,它可以完整地反转文件的内容,就像一个字符串一样
您可以随后显示输出甚至将其写入文件。代码如下:
#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;
}
tac
源代码。 - hari