【问题标题】:C converts .txt to binary file using System CallsC 使用系统调用将 .text 转换为二进制文件
【发布时间】:2016-03-06 13:14:19
【问题描述】:

我正在编写一个程序来替换 position % step = 0 所在的每个字符 作为命令行参数,我给出了1. file2. character3. step。我只能使用系统调用。这是我的主要功能:

int main(int argc, char **argv){

   assert(argc ==  4);

   int fdInput = open(argv[1], O_WRONLY);
   if(fdInput == -1)
      fatalError("Error opening input file.\n");

   char c[1];
   c[0] = argv[2][0];
   unsigned step = atoi(argv[3]);

   int fileSize;
   if((fileSize = lseek(fdInput,0,SEEK_END)) < 0)
      fatalError("Lseek error: Determining file size\n");

   if(lseek(fdInput,0,SEEK_SET) == -1)
      fatalError("Lseek error: Returning to the beginning\n");

   int i;
   for(i = 0; i*step < fileSize; i++)

      if(step - 1 > 0){
         if(lseek(fdInput, i*step - 1, SEEK_SET) == -1)
            fatalError("Lseek error: Within loop\n");

         if(write(fdInput, c, 1) != 1)
            fatalError("Writing error\n");

      }
      else {

         if(write(fdInput, c, 1) != 1)
            fatalError("Writing error.\n");
      }
      close(fdInput);
      return 0;
   }

示例:

input.txt:123456789

./output input.txt x 3 将返回 12x45x78x

问题:由于某种原因,当我第一次编译和执行时,一切正常!但是:当我第二次执行它时,它不会工作。当我尝试cat/less input.txt 它告诉我文件是二进制文件。

  • echo "123456789" &gt; input.txt -> 创建.txt 文件
  • ./output input.txt x 3 -> 12x45x78x
  • ./output input.txt x 3 -> 不会工作(程序已完成),但是:
  • less input.txt -> input.txt" may be a binary file. See it anyway?

文件如何是二进制的?它应该是纯文本文件。我在这里做错了什么?我对open 做错了吗?

【问题讨论】:

  • 我注意到的第一件事是,对我来说,即使是第一次执行也不能正常工作。文件似乎充满了大量的空字符(但替换的字符串看起来很好)。我会继续调查。
  • 哇,我意识到你正在使用这段代码生成 4GB 稀疏文件。
  • 在循环中的第一个 lseek 中,您会进行巨大的跳跃: lseek(3, 4294967295, SEEK_SET) = 4294967295 write(3, "x", 1) = 1

标签: c data-conversion


【解决方案1】:

您的第一次查找偏移量错误:

i*step - 1

使用i == 0 这将产生-1,仅考虑纯数学计算并将隐式类型转换排除在游戏之外。然后将其转换为unsignedoff_t 已签名,传递的负值应导致EINVAL,因此它必须是隐式转换),它将非常大(UINT_MAX)。结果是一个非常大(但稀疏)的文件。

哦,还有:

assert(argc ==  4);

assert 用于检查不变量,而不是用于处理不正确的用户输入。

【讨论】:

  • "i == 0 这会产生 -1" 并非如此。 int*unsigned - int --> unsigned。所以“与 i == 0 应该产生UINT_MAX
  • 嗯,我需要更好地解释这一点。我的意思是数学计算产生-1。不过,我不确定 signed * unsigned 是否会产生 unsigned 结果,这就是我没有说明的原因。我想通过笔记本电脑而不是手机上网时检查标准。
  • i*step - 1 不是在不考虑类型的情况下进行数学计算的,并且 然后 转换为 unsigned。在每个步骤中,都会考虑 value 和 tpye。 (int)0 * (unsigned)step --> (unsigned)0(unsigned)0 - (int)1 --> UINT_MAX。如果UINT_MAXoff_t 的范围内,则将一个大的正值传递给lseek()。否则,如果超出范围,则结果未定义(UB)。 IAC,您已经很好地确定了 OP 代码的问题。只是“为什么”出了问题。您的编辑有所改进,更接近原因。
  • 感谢两位的回答。
  • less 注意到有很多不可打印的字符,因此它猜测它可能是一个不打算直接查看的文件。没有“二进制文件”之类的东西(所有文件都是二进制文件);没有转换。 (二进制是一种开放模式,会影响某些字节序列在某些平台上的解释方式)
【解决方案2】:

您应该将 i 初始化为 1 而不是 0,即

for(i = 1; i*step < fileSize; i++)

否则,正如@Daniel Jour 所说,您的第一次查找偏移量将是错误的(i*step - 1 == -1,仅考虑纯数学计算并将隐式类型转换排除在游戏之外)。

此外,您应该添加 for-loop 的左大括号和右大括号以提高可读性。

【讨论】:

  • "first seek offset 会出错(i*step - 1 == -1)" --> 0*step - 1 --&gt; UINT_MAX.
  • @chux 更新了我的答案以反映 Daniel Jour 的答案。我的意思是一样的。谢谢。
  • 感谢您的回答。
猜你喜欢
  • 2012-02-05
  • 1970-01-01
  • 2015-05-29
  • 2016-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 2012-08-12
相关资源
最近更新 更多