【问题标题】:Write() to file descriptor disappearing when read()写入()到文件描述符在读取()时消失
【发布时间】:2019-04-13 14:22:00
【问题描述】:

所以我现在正在我的程序的服务器端工作,我想做以下事情:

1) 以读/写模式打开文件

2) 在文件末尾追加一个单词(WORD)

3) [我相信我已经完成了所有这部分] 打开一个管道,创建一个子进程,让它直接从文件(文件描述符)中读取,执行一个命令,并将结果发送到 write/管道的输出。父进程从管道的读取/输入中读取,并将信息放入缓冲区以发送回客户端。

我遇到的问题是附加部分。我很确定它会附加到文件中(在现有文本和我的 WORD 之间有一个换行符),因为当我直接打开文本文件时它就在那里。但是当我尝试从缓冲区打印它时,它不存在。我尝试在写入并重新打开后关闭文件描述符,但它不存在。我试过 strcat 而不是写入文件描述符,但它不存在。

  #define WORD "WORD"
  #define BUFFERLENGTH 512
  char buffer[BUFFERLENGTH];

  int fileDesc = open (filePath, O_RDWR|O_APPEND, 0660);
  if (fileDesc <= 0){
    write(clientDesc, ERRORMSG, BUFFERLENGTH);
    exit(EXIT_FAILURE);
  }

  read(fileDesc,buffer,BUFFERLENGTH);

  long length  = lseek(fileDesc,0,SEEK_END);
  int status  = write(fileDesc,WORD,sizeof(WORD)-1);

  read(fileDesc, buffer, BUFFER_LEN+1);
  printf("new text: %s\n", buffer); //WORD does not show up at the end of file as intended

我真的有什么误解吗?

也许我不完全理解 open()、read()、write() 和 lseek() 是如何工作的,但如果有人可以帮助向我解释为什么这不能按预期工作,那就太好了赞赏。过去一周我一直在为此苦苦挣扎,目前我打开的用于搜索解决方案的选项卡数量非常可悲。

【问题讨论】:

    标签: c file-descriptor read-write lseek


    【解决方案1】:

    在您拨打write() 之后,您将位于文件的末尾,因此read() 将无法读取任何内容。如果您希望能够从中读取任何内容,则需要 lseek() 到文件中较早的位置。

    您应该检查来自read()(以及几乎所有其他系统调用,就此而言)的返回,并在出现错误的情况下使用perror() 或类似名称,这将有助于您了解发生了什么当您看到出乎意料的行为时开启。

    修改你的程序:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    
    #define WORD "WORD"
    #define BUFFERLENGTH 512
    
    int main(void)
    {
        char * filePath = "testfile.txt";
        char buffer[BUFFERLENGTH] = {0};
    
        // Open file.
    
        int fd = open(filePath, O_RDWR | O_APPEND, 0660);
        if (fd < 0) {
            perror("couldn't open file");
            return EXIT_FAILURE;
        }
    
        // Write word to end.
    
        int status = write(fd, WORD, strlen(WORD));
        if ( status < 0 ) {
            perror("couldn't write");
            return EXIT_FAILURE;
        }
    
        // Seek to start of file.
    
        long length = lseek(fd, 0, SEEK_SET);
        if ( length < 0 ) {
            perror("couldn't lseek");
            return EXIT_FAILURE;
        }
    
        // Read contents of file.
    
        status = read(fd, buffer, BUFFERLENGTH - 1);
        if ( status < 0 ) {
            perror("couldn't read");
            return EXIT_FAILURE;
        }
    
        // Print buffer.
    
        printf("file contents: %s\n", buffer);
    
        return 0;
    }
    

    产量:

    paul@mac:scratch$ touch testfile.txt
    paul@mac:scratch$ ./file
    file contents: WORD
    paul@mac:scratch$ ./file
    file contents: WORDWORD
    paul@mac:scratch$ ./file
    file contents: WORDWORDWORD
    paul@mac:scratch$ ./file
    file contents: WORDWORDWORDWORD
    paul@mac:scratch$
    

    如果您实际上只想看到新内容,那么您需要lseek() 到文件开头以外的某个点。由于成功的write() 将返回写入的字节数,您可以使用此值从文件末尾偏移:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    
    #define BUFFERLENGTH 512
    
    int main(int argc, char * argv[])
    {
        if ( argc < 2 ) {
            fprintf(stderr, "you need to enter a word argument\n");
            return EXIT_FAILURE;
        }
    
        char * filePath = "testfile.txt";
        char buffer[BUFFERLENGTH] = {0};
    
        // Open file.
    
        int fd = open(filePath, O_RDWR | O_APPEND, 0660);
        if ( fd < 0 ) {
            perror("couldn't open file");
            return EXIT_FAILURE;
        }
    
        // Write word to end.
    
        int status = write(fd, argv[1], strlen(argv[1]));
        if ( status < 0 ) {
            perror("couldn't write");
            return EXIT_FAILURE;
        }
    
        // Seek to point before last write.
    
        long length = lseek(fd, -status, SEEK_END);
        if ( length < 0 ) {
            perror("couldn't lseek");
            return EXIT_FAILURE;
        }
    
        // Read from there to end of file.
    
        status = read(fd, buffer, BUFFERLENGTH - 1);
        if ( status < 0 ) {
            perror("couldn't read");
            return EXIT_FAILURE;
        }
    
        // Print buffer.
    
        printf("new text: %s\n", buffer);
    
        return 0;
    }
    

    屈服:

    paul@mac:scratch$ rm testfile.txt
    paul@mac:scratch$ touch testfile.txt
    paul@mac:scratch$ ./file2 these
    new text: these
    paul@mac:scratch$ ./file2 are
    new text: are
    paul@mac:scratch$ ./file2 some
    new text: some
    paul@mac:scratch$ ./file2 words
    new text: words
    paul@mac:scratch$ cat testfile.txt
    thesearesomewordspaul@mac:scratch$ 
    

    【讨论】:

    • 感谢您的建议!我想我当时感到困惑的是,在写入文件之后,读取/打印将如何从文件的开头打印并在 WORD 之前停止。如果您的建议是我从最后开始阅读,它不应该什么都没有打印吗?我也尝试关闭文件并再次打开以阅读,我也假设从头开始阅读,但结尾文本没有打印:\ 也许我不明白
    • @purpledots:你需要展示一个完整的可编译程序以及你正在使用的输入和你得到的输出,以便我能够解释,我可以' t 根据您展示的内容重现您所描述的内容。
    • @purpledots:你需要flush()这4个字符出缓冲区吗?您是否更改了读取长度以容纳额外的字符?我注意到您的代码中有两个不同的缓冲区长度常量:BUFFERLENGTHBUFFER_LEN
    • @Omegaman:带有read()write() 和朋友的 Unix 文件 i/o 没有缓冲(操作系统级别的磁盘块缓冲对程序员来说是透明的),所以不会有任何东西需要冲洗,这里。
    • @Omegaman 我对 flush() 不太熟悉,但这是为了清除缓冲区吗?我不是想清除它,只是显示里面有什么。哎呀,是的,我在我的代码中也发现了这一点,谢谢:)
    猜你喜欢
    • 2012-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-12
    • 2020-05-30
    • 2019-06-20
    • 1970-01-01
    • 2011-08-16
    相关资源
    最近更新 更多