【问题标题】:Writing a New Line to a File将新行写入文件
【发布时间】:2013-03-02 07:40:33
【问题描述】:

我目前正在使用以下命令为我的程序写入输出文件。我想获取存储在二维数组中的字符串并将其写入我设置的输出文件,即“url_storage.txt”。

下面的示例显示了我如何在程序开始附近设置文件(即初始文件描述符声明和对 open(...) 的调用)并显示对 write(...) 的主要调用,这发生在一个while循环中(从二维数组中的每个槽写入,或字符串/字符数组的集合)。我的问题是我想在每个字符串之后插入一个 NEWLINE 字符,但是,下面的代码不会产生一个文件,每个字符串(或每次写入的结果)都在单独的行上。有没有什么简单的方法可以让 write 函数识别我希望它遵守换行符?我还发现有一个函数 lseek(...) 可以调整我的文件位置指针(看起来它对于换行调整并不是很有用)。关于如何让它指向下一行的任何建议?

int fd2 = open("/directory/path/to/target/output/file/url_storage.txt", O_WRONLY, O_CREAT, 00777);

...
while(...){
      ...
      (void) write(fd2, (" %s \n", matches[ind]), strlen(matches[ind]));
}

【问题讨论】:

    标签: c file file-io newline file-descriptor


    【解决方案1】:

    这个:

    write(fd2, (" %s \n", matches[ind]), strlen(matches[ind]));
    

    不做你认为它做的事。您将printf()write() 混淆了。 '格式字符串'" %s \n" 是逗号表达式的第一部分,实际上被丢弃了。仅将字符串写入文件。您必须单独编写换行符:

    if (write(fd2, " ", 1) != 1 ||
        write(fd2, matches[ind], strlen(matches[ind])) != strlen(matches[ind]) ||
        write(fd2, " \n", 2) != 2)
        ...something went wrong...
    

    或者考虑使用 POSIX dprintf(),它类似于 fprintf(),但写入文件描述符而不是文件流。

    if (dprintf(fd2, " %s \n", matches[ind]) != strlen(matches[ind])+3)
        ...something went wrong...
    

    我尝试遵循您的意图,在字符串之前和之后添加一个空格,但如果它是我的代码,至少会省略尾随空格(几乎不需要在换行符之前有空格任何情况下——除了-- 之后,它标志着电子邮件中签名的开始。前面的空格可能需要将字符串与之前的字符串分开。但是,我可能会写:

    if (dprintf(fd2, "%s\n", matches[ind]) != strlen(matches[ind])+1)
        ...something went wrong...
    

    或具有单独的write() 调用的等效项。


    顺便说一句,你写了相当于:

     const char path[] = "/directory/path/to/target/output/file/url_storage.txt";
     int fd2 = open(path, O_WRONLY, O_CREAT, 00777);
    

    由于复杂的历史原因,open() 的原型是int open(const char *path, int flag, ...);,但只有 2 或 3 个参数是有效的,而你使用了 4 个。你应该这样写:

     int fd2 = open(path, O_WRONLY|O_CREAT, 0777);
    

    但是编译器不能轻易地诊断出错误;毕竟,原型说的是“任意数量的参数”。此外,除非您正在编写 shell 脚本,否则该文件不应该是可执行的(所以 0666 而不是 0777),我愿意争辩说它也不应该是公开可写的,所以 0664 甚至 0644 会更好,尽管umask 值可用。顺便说一句,使用像 path 这样的变量而不是文字的一个优点是,如果您不必重复字符串文字,则使用文件名更容易报告有意义的错误消息。

    【讨论】:

    • 嗯,dprintf(...) 看起来确实是一个很有前途的选择,但是它没有用。我试过:dprintf(fd2, (" %s \r\n", matches[ind]));(查了一下,它看起来很像一个普通的打印函数,只是将文件描述符作为它的第一个参数)我得到了相同的结果,没有换行。有什么建议?我的最后一个选择是尝试进行后续调用,在换行符 \n 中写入和写入,看看会发生什么。
    • 您使用的是 Windows 机器还是 Unix 机器?在 Windows 上,printf() 系列通常会为您处理行尾,即使您只是在代码中使用 \n,也要确保结尾是 \r\nwrite() 函数绝对不执行该映射。我猜dprintf()printf() 的关系比write() 更接近。因此,请尝试在输出中添加\r,正如其他回答者所建议的那样。
    • 好吧,所以我决定采用你的方法,只是简单地省略空格(最初它们在那里只是为了看看我是否可以在 URL 字符串之间获得任何间距 - 这不是发生)。这很有效,并且给了我一个新行上的每个字符串,另外,我喜欢在 if 语句中调用 write 来检查函数是否工作。我在 Windows 机器上(使用 Cygwin 环境),但一直在 sftp-ing/远程访问 Linux 帐户。在我的 Windows 机器上编写代码时,我使用 Linux 遥控器上的命令行来编译和运行代码。
    • 顺便说一下,我在 dprintf(...) 的格式字符串中测试了两种换行符方法:'\n' 和 '\r\n' 都有效。我想使用后者会更安全,并且可以在 Linux 和 Windows 环境中工作?
    • 除非你有充分的理由不这样做,否则我建议使用fopen()fprintf();我想这对你来说会更简单。 Unix (Linux) 上的回车 (\r) 有点麻烦。它们有效,但不可取。确保 fopen() 文件处于文本模式(不是二进制模式,因此模式字符串中没有“b”)和源代码中的 \n 在 Linux 上运行时应该在 Linux 上正常工作,并且在运行时应该在 Windows 上正常工作在 Windows 上。
    猜你喜欢
    • 2011-12-17
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 2012-06-04
    • 1970-01-01
    • 2016-05-26
    相关资源
    最近更新 更多