使字符在C中的文件中超过某个点

时间:2014-09-09 21:17:25

标签: c system-calls

我想从名为WWW的文件中获取位置900之后的所有字符,并将所有这些字符放在一个数组中:

 //Keep track of all characters past position 900 in WWW.
 int Seek900InWWW = lseek(WWW, 900, 0); //goes to position 900 in WWW
 printf("%d \n", Seek900InWWW);  
 if(Seek900InWWW < 0)
   printf("Error seeking to position 900 in WWW.txt");
 char EverythingPast900[appropriatesize];
 int NextRead;
 char NextChar[1];
 int i = 0;
 while((NextRead = read(WWW, NextChar, sizeof(NextChar))) > 0) {
   EverythingPast900[i] = NextChar[0];  
   printf("%c \n", NextChar[0]);
   i++;
 }

我尝试创建一个长度为1的char数组,因为read系统调用需要一个指针,我不能使用常规char。上面的代码不起作用。实际上,它不会像循环所期望的那样向终端打印任何字符。我认为我的逻辑是正确的,但也许对幕后发生的事情的误解是让我难以理解的。或许我错过了一些简单的事情(希望不是)。

4 个答案:

答案 0 :(得分:5)

如果您已经知道要读取多少字节(例如在appropriatesize中),那么只需一次读入多个字节,而不是一次读取一个字节。

char everythingPast900[appropriatesize];
ssize_t bytesRead = read(WWW, everythingPast900, sizeof everythingPast900);

if (bytesRead > 0 && bytesRead != appropriatesize)
{
    // only everythingPast900[0] to everythingPast900[bytesRead - 1] is valid
}

答案 1 :(得分:2)

我制作了代码的测试版,并添加了您遗漏的内容。你为什么要把它们抛弃?

我还创建了一个名为www.txt的文件,其中有一百行“这是一条测试线”。在它。

我发现了一个潜在的问题,具体取决于appropriatesize值的大小和文件的大小。如果你写过EverythingPast900的末尾,你有可能在你产生任何要显示的输出之前杀死你的程序并使其崩溃。这可能发生在Windows上,根据您使用的库,stdout可能不会进行行缓冲。

See the MSDN setvbuf page,特别是“对于某些系统,这提供了行缓冲。但是,对于Win32,行为与_IOFBF - 完全缓冲相同。”

这似乎有效:

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int WWW = open("www.txt", O_RDONLY);
    if(WWW < 0)
        printf("Error opening www.txt\n");
    //Keep track of all characters past position 900 in WWW.
    int Seek900InWWW = lseek(WWW, 900, 0); //goes to position 900 in WWW
    printf("%d \n", Seek900InWWW);  
    if(Seek900InWWW < 0)
        printf("Error seeking to position 900 in WWW.txt");
    int appropriatesize = 1000;
    char EverythingPast900[appropriatesize];
    int NextRead;
    char NextChar[1];
    int i = 0;
    while(i < appropriatesize && (NextRead = read(WWW, NextChar, sizeof(NextChar))) > 0) {
        EverythingPast900[i] = NextChar[0];  
        printf("%c \n", NextChar[0]);
        i++;
    }
    return 0;
}

答案 2 :(得分:1)

如另一个答案中所述,读取多个字节。背后的理论&#34;缓冲&#34;是因为磁盘I / O(或网络I / O)与内存速度和CPU速度相比有多慢,所以减少了读/写操作的数量。看看它好像是代码并考虑哪个更快:将文件大小增加1倍N次并单独写N个字节,或者将N加到文件大小一次并一次写N个字节?

值得一提的另一件事是read可能读取的内容少于您请求的字节数,即使有更多要阅读的内容。 answer written by @dreamlax说明了这一事实。如果需要,可以使用循环来读取尽可能多的字节,填充缓冲区。请注意,我使用了一个函数,但您可以在主代码中执行相同的操作:

#include <sys/types.h>

/* Read from a file descriptor, filling the buffer with the requested
 * number of bytes. If the end-of-file is encountered, the number of
 * bytes returned may be less than the requested number of bytes.
 * On error, -1 is returned. See read(2) or read(3) for possible
 * values of errno.
 * Otherwise, the number of bytes read is returned.
 */
ssize_t
read_fill (int fd, char *readbuf, ssize_t nrequested)
{
  ssize_t nread, nsum = 0;

  while (nrequested > 0
         && (nread = read (fd, readbuf, nrequested)) > 0)
    {
      nsum += nread;
      nrequested -= nread;
      readbuf += nread;
    }

  return nsum;
}

请注意,缓冲区不是以空值终止的,因为并非所有数据都必须是文本。您可以将buffer_size - 1作为请求的字节数传递,并使用返回值在必要时添加空终止符。这在与期望以null结尾的字符串的函数进行交互时非常有用:

char readbuf[4096];
ssize_t n;
int fd;

fd = open ("WWW", O_RDONLY);
if (fd == -1)
  {
    perror ("unable to open WWW");
    exit (1);
  }

n = lseek (fd, 900, SEEK_SET);
if (n == -1)
  {
    fprintf (stderr,
             "warning: seek operation failed: %s\n"
             "  reading 900 bytes instead\n",
             strerror (errno));
    n = read_fill (fd, readbuf, 900);
    if (n < 900)
      {
        fprintf (stderr, "error: fewer than 900 bytes in file\n");
        close (fd);
        exit (1);
      }
  }

/* Read a file, printing its contents to the screen.
 *
 * Caveat:
 * Not safe for UTF-8 or other variable-width/multibyte
 * encodings since required bytes may get cut off.
 */
while ((n = read_fill (fd, readbuf, (ssize_t) sizeof readbuf - 1)) > 0)
  {
    readbuf[n] = 0;
    printf ("Read\n****\n%s\n****\n", readbuf);
  }
if (n == -1)
  {
    close (fd);
    perror ("error reading from WWW");
    exit (1);
  }

close (fd);

我也可以避免空终止操作并填充缓冲区的所有4096个字节,在这种情况下选择使用printf格式说明符的精度部分,从{{1}更改格式规范到%s。但是,对于异常大的缓冲区(可能由%.4096s分配以避免堆栈溢出),这可能不可行,因为缓冲区大小可能无法用malloc类型表示。

此外,您可以使用常规的int

char

显然你并不知道一元char c; nread = read (fd, &c, 1); 运算符获取其操作数的任何变量的地址,创建一个指向类型指针的值{typeof var}?无论哪种方式,它占用相同数量的内存,但一次读取1个字节通常不会像我所解释的那样完成。

答案 3 :(得分:-2)

混合声明和代码是不行的。此外,不,这不是一个有效的声明。 C应该按照它的不同定义来抱怨它。

你想要的是为你的char buffer []动态分配内存。你必须使用指针。

http://www.ontko.com/pub/rayo/cs35/pointers.html

然后阅读本文。

http://www.cprogramming.com/tutorial/c/lesson6.html

然后研究一个名为memcpy()的函数。

享受。

通读该指南,您应该能够以完全不同的方式解决问题。

Psuedo代码。

declare a buffer of char(pointer related)
allocate memory for said buffer(dynamic memory related)

Find location of where you want to start at
point to it(pointer related)
Figure out how much you want to store(technically a part of allocating memory^^^)
Use memcpy() to store what you want in the buffer