【问题标题】:How to perform bitwise operations on files in linux?如何在 linux 中对文件执行按位运算?
【发布时间】:2011-10-16 20:57:30
【问题描述】:

我想对 Linux 中的文件进行一些按位运算(例如异或两个文件),但我不知道该怎么做。是否有任何命令?

我们将不胜感激。

【问题讨论】:

  • 你承诺接受答案吗?
  • 读取块,将操作符应用于块中的所有数据,写入块
  • @unkulunkulu @phihag 是的,当然我不知道,我现在才找到,谢谢;)

标签: c++ linux command bitwise-operators


【解决方案1】:

您可以使用mmap 映射文件,对映射的内存应用按位运算,然后关闭它。

或者,将块读入缓冲区,对缓冲区应用操作,然后写出缓冲区也可以。

这是一个反转所有位的示例(C,不是 C++;因为除了错误处理之外的所有内容都是相同的):

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char* argv[]) {
    if (argc != 2) {printf("Usage: %s file\n", argv[0]); exit(1);}

    int fd = open(argv[1], O_RDWR);
    if (fd == -1) {perror("Error opening file for writing"); exit(2);}

    struct stat st;
    if (fstat(fd, &st) == -1) {perror("Can't determine file size"); exit(3);}

    char* file = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
                      MAP_SHARED, fd, 0);
    if (file == MAP_FAILED) {
        perror("Can't map file");
        exit(4);
    }

    for (ssize_t i = 0;i < st.st_size;i++) {
        /* Binary operation goes here.
        If speed is an issue, you may want to do it on a 32 or 64 bit value at
        once, and handle any remaining bytes in special code. */
        file[i] = ~file[i];
    }

    munmap(file, st.st_size);
    close(fd);
    return 0;
}

【讨论】:

  • 非常感谢您的回答。您介意再解释一下第一个解决方案吗?
  • @Sina 我添加了一个示例程序(我不相信我的 C++ 技能,所以我用 C 编写了它——你可能想要 C++ 化错误处理)。这有帮助吗?
  • 非常感谢,很有用:)
  • @Sina 首先,计算你有多少条目(num = st.size/sizeof(entry),其中entryint32_t 左右)。将file 转换为指向所需类型的指针,并在for 循环中将st.st_size 替换为num。不要忘记处理剩余的st.st_size - num * sizeof(entry) 字节!
  • @Sina 您可以使用strtol 将十六进制字符串参数转换为数字。 no way 可以在不完全重写的情况下写入文件的头部。你can append to a memory-mapped file.
【解决方案2】:

通过互联网快速搜索发现Monolith,这是一个专门用于异或两个文件的开源程序。我发现它是因为 Bruce Schneier 在博客上写过它,而且这样做的目的似乎是合法的。

【讨论】:

    【解决方案3】:

    感谢“phihag”,此代码用于对 2 个文件进行二进制操作。
    示例 1:您有两个文件并想比较这两个文件,因此您对它们进行二进制 XOR。
    Ex.2:您已经使用 jdownloader 或类似的东西下载了一个文件,并且您将未完成的下载移动到另一个文件夹,然后下载管理器继续未完成的部分并创建另一个文件。所以你有两个单独的文件,它们可以互相完成。现在,如果您对这两个文件执行二进制 OR,您就有了一个完整的文件。

    警告:较大的文件将被操作结果覆盖。

    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    #include <string.h>
    
    int main(int argc, char* argv[])
    {
        int FP1 = 0, FP2 = 0;
        struct stat St1, St2;
        char *File1 = NULL, *File2 = NULL;
        int Rn = 0;
    
        if (argc != 4)
        {
            printf("Usage: %s File1 File2 Operator\n", argv[0]);
            exit(1);
        }
    
        //Opening and mapping File1
        FP1 = open(argv[1], O_RDWR);
        if (FP1 == -1)
        {
            perror("Error opening file1 for writing");
            exit(2);
        }
    
        if (fstat(FP1, &St1) == -1)
        {
            perror("Can't determine file1 size");
            exit(3);
        }
    
        File1 = (char*) mmap(NULL, St1.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, FP1, 0);
        if (File1 == MAP_FAILED)
        {
            perror("Can't map file1");
            exit(4);
        }
        //======================
    
        //Opening and mapping File2
        FP2 = open(argv[2], O_RDWR);
        if (FP2 == -1)
        {
            perror("Error opening file2 for writing");
            exit(2);
        }
    
        if (fstat(FP2, &St2) == -1)
        {
            perror("Can't determine file2 size");
            exit(3);
        }
    
        File2 = (char*) mmap(NULL, St2.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, FP2, 0);
        if (File2 == MAP_FAILED)
        {
            perror("Can't map file2");
            exit(4);
        }
        //======================
    
        //Binary operations
        ssize_t i = 0;
        switch (*(argv[3]))
        {
            case '|':
                if (St1.st_size <= St2.st_size)
                    for (i = 0; i < St1.st_size; i ++)
                        File2[i] = File1[i] | File2[i];
                else
                    for (i = 0; i < St2.st_size; i ++)
                        File1[i] = File1[i] | File2[i];
                break;
            case '&':
                if (St1.st_size <= St2.st_size)
                    for (i = 0; i < St1.st_size; i ++)
                        File2[i] = File1[i] & File2[i];
                else
                    for (i = 0; i < St2.st_size; i ++)
                        File1[i] = File1[i] & File2[i];
                break;
            case '^':
                if (St1.st_size <= St2.st_size)
                    for (i = 0; i < St1.st_size; i ++)
                        File2[i] = File1[i] ^ File2[i];
                else
                    for (i = 0; i < St2.st_size; i ++)
                        File1[i] = File1[i] ^ File2[i];
                break;
            default:
                perror("Unknown binary operator");
                exit(5);
        }
        //======================
    
        munmap(File1, St1.st_size);
        munmap(File2, St2.st_size);
        close(FP1);
        close(FP2);
    
        //Renaming the changed file and make output
        char Buffer[1024];
        if (St1.st_size <= St2.st_size)
        {
            Rn = system(strcat(strcat(strcat(strcat(strcpy(Buffer, "mv \""), argv[2]), "\" \""), argv[2]),"-Mapped\""));
            if (Rn == -1)
            {
                perror("Unable to rename the new file.");
                exit(6);
            }
            else
                printf("%s is mapped.\n", argv[2]);
        }
        else
        {
            Rn = system(strcat(strcat(strcat(strcat(strcpy(Buffer, "mv \""), argv[1]), "\" \""), argv[1]),"-Mapped\""));
            if (Rn == -1)
            {
                perror("Unable to rename the new file.");
                exit(6);
            }
            else
                printf("%s is mapped.\n", argv[1]);
        }
        //======================
    
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      对于那些喜欢 Python 脚本的人:

      #!/usr/bin/env python3
      
      import binascii
      import sys
      
      blocksize = 4096
      
      input1 = open(sys.argv[1], 'rb')
      input2 = open(sys.argv[2], 'rb')
      output = open(sys.argv[3], 'wb')
      
      while True:
          block1 = input1.read(blocksize)
          block2 = input2.read(blocksize)
          if not block1 and not block2:
              break  # reached EOF in both files
          if len(block1) != len(block2):
              sys.stderr.write('Premature EOF, truncating to shorter file\n')
              block1 = block1[:min(len(block1), len(block2))]
              block2 = block2[:min(len(block1), len(block2))]
          # convert to large integer
          int1 = int(binascii.hexlify(block1), 16)
          int2 = int(binascii.hexlify(block2), 16)
          # apply logical operator: xor
          int_o = int1 ^ int2
          # covert back to binary
          hexformat = '%%0%dx' %(2*len(block1))  # e.g. '%0512x' for 256 bytes
          block_o = binascii.unhexlify(hexformat %int_o)
          output.write(block_o)
      
      output.close()
      input1.close()
      input2.close()
      

      对于不同长度的文件,它会发出警告并停止。在某些应用程序中,最好用零字节填充较短的输入或回绕到输入文件的开头。这可以在命令行上通过将较短的文件与自身或/dev/zero 的输出连接起来来实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-15
        • 1970-01-01
        • 1970-01-01
        • 2014-12-23
        • 2017-04-01
        • 2013-06-11
        • 1970-01-01
        相关资源
        最近更新 更多