c语言 - 从另一个进程写入的文件"edge"读取(使用fallocate)



我有两个进程:和一个"阅读器">

写入器使用fallocate(2)首先创建一个固定长度的文件(全是0),然后写入器向该文件写入数据。

我想让reader进程读取文件直到"边缘"。(写入器最后写入数据的文件偏移量),然后等待写入器添加更多数据。

这里有一些简单的程序示例,供作者和读者使用。注意,阅读器读取的速度会稍微快一点,所以在某些时候会碰到文件的边缘。当它遇到这种情况时,它应该查找一个数据元素并再次尝试,直到它读取到一个非零数据元素。

它不工作。似乎读者只能寻找并成功阅读一次。之后,它总是从当前文件位置读取0。(见下面的日志)

但是…如果我使用另一个终端窗口将文件复制到其他地方,则所有预期的数据都存在。所以看起来数据正在写入,但它不是可靠地读取

有什么建议吗?

EDIT/SOLUTION

John Bollinger的建议解决了这个问题:

fopen之后和开始阅读之前添加这行:

setvbuf(fp, NULL, _IONBF, 0);

作家过程

/*
  g++ fWriter.cpp -o fWriter -g -pg
*/
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
    printf("WRITER LAUNCHEDn");
    const int N = 100;
    FILE *fp = fopen("/tmp/someFile", "w");
    if (!fp)
    {
        perror("fopen");
        exit(1);
    }
    int   itemLen = sizeof(uint32_t);
    off_t     len = itemLen * N;
    int fd = fileno(fp);
    if (fallocate(fd, 0, 0, len) == -1)
    {
        fprintf(stderr, "fallocate failed: %sn", strerror(errno));
        exit(1);
    }
    for (uint32_t i = 1; i <= N; i++)
    {
        int numBytes = fwrite((void*)&i, 1, itemLen, fp);
        if (numBytes == itemLen)
            printf("[%u] Wrote %un", i, i);
        else
            printf("Write errorn");
        fflush(fp);
        sleep(1);
    }
    fclose(fp);
    printf("WRITER COMPLETEn");
}

读者过程

/*
  g++ fReader.cpp -o fReader -g -pg
*/
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
    printf("READER LAUNCHEDn");
    FILE *fp = fopen("/tmp/someFile", "r");
    if (!fp)
    {
        perror("fopen");
        exit(1);
    }
    
    // New!
    setvbuf(fp, NULL, _IONBF, 0);
    int   i = 1;
    int   itemLen = sizeof(uint32_t);
    while (!feof(fp))
    {
        uint32_t val;
        int numBytes = fread((void*)&val, 1, itemLen, fp);
        if (numBytes != itemLen)
        {
            printf("Short readn");
            continue;
        }
        printf("[%d] Read %un", i, val);
        // wait for data
        if (val == 0)
        {
            off_t curPos = ftello(fp);
            off_t newPos = curPos - itemLen;
            printf("Seek and try again. newPos %dn", newPos);
            fseeko(fp, newPos, SEEK_SET);
        }
        i++;
        //usleep(1100000);
        usleep(900000);
    }
    fclose(fp);
}

读者日志

READER LAUNCHED
[1] Read 1
[2] Read 2
[3] Read 3
[4] Read 4
[5] Read 5
[6] Read 6
[7] Read 0
Seek and try again. newPos 24
[8] Read 7
[9] Read 8
[10] Read 9
[11] Read 10
[12] Read 11
[13] Read 0
Seek and try again. newPos 44
[14] Read 0
Seek and try again. newPos 44
[15] Read 0
Seek and try again. newPos 44
[16] Read 0
Seek and try again. newPos 44
[17] Read 0
Seek and try again. newPos 44
[18] Read 0
Seek and try again. newPos 44
[19] Read 0
Seek and try again. newPos 44
[20] Read 0
Seek and try again. newPos 44
[21] Read 0
Seek and try again. newPos 44
[22] Read 0
Seek and try again. newPos 44

流(由stdio.h FILE对象表示的任何东西)可以完全缓冲,行缓冲或不缓冲。默认情况下,连接到常规文件的流将被完全缓冲。这当然就是为什么你的读者在当前文件位置读了一堆零之后,没有注意到作者已经覆盖了其中的一些。读取器将不再从底层文件中查询已经缓冲的文件区域的数据。

在这种情况下,读者可以而且应该使用setvbuf()将文件的缓冲模式改为无缓冲。

最新更新