我想要做的是读取一个数据远远超过屏幕尺寸的文件,并根据用户的响应逐页显示。
fp = fopen(empRecord.dat,"rb"); // read mode
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n",empRecord.dat);
while( ( ch = fgetc(fp) ) != EOF )
printf("%c",ch);
fclose(fp);
有什么建议吗?
答案 0 :(得分:1)
这听起来像是家庭作业,所以这里有一些想法指导你(没有直接给你解决方案):
如果你提出正确的问题,问题通常会自行解决。
答案 1 :(得分:0)
当使用返回int的fgetc时,你应该对读取的字符数设置一个自限制。
while( ( ch = fgetc(fp) ) != EOF )
printf("%c",ch);
你所采取的限制,就像一页的100个字符一样。
int i=0;
while( ( ch = fgetc(fp) ) != EOF )
{
i++;
printf("%c",ch);
if(i==100)
{
printf("you want to see more...(1/0)");
scanf("%d",choice);
if(choice!=1)
break;
else
clrscr();
}
}
答案 2 :(得分:0)
我建议一次选择要在屏幕上打印的行数。在这里,我一次在屏幕上选择50行,然后显示器等待用户的输入。
int cnt =0;
while( (fgets(buf,sizeof(buf),fp) ) != NULL )
{
printf("%s",buf);
if(cnt == 50)
{
getchar();
cnt =0;
}
cnt ++;
}
答案 3 :(得分:0)
让我在Peter Schneider's comment上稍微扩展一下。不要重新发明轮子。您的用户将更加满意他们已经知道如何从其他程序配置和使用的解决方案(以及接口)。 UNIX的做事方式是做一件事,做得好。显示输出页面的程序称为 pager 。曾经是more,但现在less是一个更好的选择。
寻呼机将通过其标准输入流接收要显示的内容,然后以任何奇特的方式将其呈现给用户。您应该将寻呼机程序的选择留给用户。执行此操作的一种好方法是检查环境变量PAGER
以获取作为寻呼机执行的命令。如果您这样做,请注意不能始终信任环境。如果您的程序是stuid()
,那么从环境变量执行代码是一个非常糟糕的主意,因此在这种情况下您最好忽略它。有些人喜欢提供更加特殊的MYPROGRAM_PAGER
变量,只有在未设置的情况下才会检查更一般的PAGER
变量。
您应该检查的另一件事是标准输出isatty()
。如果不是,只需立即转储所有输出。由于它将被重定向到一个文件,它也不会溢出屏幕(因此寻呼机不会有用),用户也不会愿意甚至无法点击输入(因此寻呼机实际上会做坏事)。
生成的C程序看起来应该很简单。
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int
produce_output(FILE *const stream, const unsigned lines);
int
main(const int argc, const char *const *const argv)
{
unsigned lines;
if (argc != 2)
{
fprintf(stderr, "error: wrong number of arguments\n");
return EXIT_FAILURE;
}
else
{
char * endptr;
long val = strtol(argv[1], &endptr, 0);
if (*endptr != '\0' || val < 0)
{
fprintf(stderr, "error: not a non-negative integer: %s\n", argv[1]);
return EXIT_FAILURE;
}
lines = val;
}
if (isatty(fileno(stdin)) && isatty(fileno(stdout)))
{
const char * pager_command = NULL;
FILE * pager_pipe = NULL;
const char *const env_vars[] = {"MYPROG_PAGER", "PAGER", NULL};
unsigned i;
for (i = 0; env_vars[i] != NULL; ++i)
{
if ((pager_command = secure_getenv(env_vars[i])) != NULL)
break;
}
if (pager_command == NULL)
pager_command = "less -XRF"; /* sane default */
pager_pipe = popen(pager_command, "w");
if (pager_pipe == NULL)
{
fprintf(stderr,
"error: popen(\"%s\", \"w\"): %s\n",
pager_command, strerror(errno));
return EXIT_FAILURE;
}
/* Write everything to the pager at once. */
if (produce_output(pager_pipe, lines) < 0)
fprintf(stderr, "warning: I/O error: %s\n", strerror(errno));
if (pclose(pager_pipe) < 0)
{
fprintf(stderr, "error: pclose(): %s\n", strerror(errno));
return EXIT_FAILURE;
}
}
else
{
/* Write everything to stdout at once. */
if (produce_output(stdout, lines) < 0)
fprintf(stderr, "warning: I/O error: %s\n", strerror(errno));
}
return EXIT_SUCCESS;
}
int
produce_output(FILE *const stream, const unsigned lines)
{
unsigned i;
for (i = 1; i <= lines; ++i)
{
const char * suffix;
switch(i)
{
case 1: suffix = "st"; break;
case 2: suffix = "nd"; break;
case 3: suffix = "rd"; break;
default: suffix = "th"; break;
}
if (fprintf(stream, "This is the %d%s line of output.\n", i, suffix) < 0)
return -1;
}
if (fflush(stream) < 0)
return -1;
return lines;
}
secure_getenv
是getenv
的GNU扩展,它封装检查环境是否可以信任。
如果您想让您的程序更加健壮,您可以实现自己的简单寻呼机,并在外部工具不可用时将其用作后备。在上面的例子中,我简单地回到了硬编码的默认值。
要测试您的计划,请考虑以下情况。
./myprog 10 # short amount of output
./myprog 1000 # large amount of output
PAGER='less -M' ./myprog 100 # use 'less -M' as pager
MYPROG_PAGER='cat' ./myprog 100 # use 'cat' as a "pager"
MYPROG_PAGER='cat' PAGER='less -M' ./myprog 100 # use 'cat' as a "pager"
./myprog 100 | cat # output is not at TTY
./myprog 100 > /dev/full # output is a bad file
sudo chown root:root myprog
sudo chmod u+s myprog
./myprog 100 # use default pager
PAGER='silly' ./myprog 100 # must ignore 'silly' in setuid'ed program
我在这个问题上花了相当多的细节,因为到目前为止最令我烦恼的是程序与用户交互不畅。不幸的是,许多编程教程都是从用户交互的可怕例子开始的,可能是因为作者从未实际使用过命令行工具。在许多(如果不是全部)命令行工具中,一致的良好用户体验是我认为可用计算机最重要的方面。