从txt文件中读取字符,编码,写入二进制文件

Reading characters from a txt file, encoding, and writing into a binary file

我正在编写一个程序,一次从文本文件中读取 4 个字符,将它们打包成一个整数,'encrypt' 将整数向右移动 3 个单位,然后写入将加密的整数转换为二进制文件。

原代码:

#include <stdio.h>
#include <limits.h>
#include "encoding.h"

#define KEY 3

int encrypt(int a); 
int pack(char a, char b, char d, char c);

void encoding(char itxt[], char obin[]){ 

        char four[4];

        FILE *inp=fopen(itxt,"r");
        if(!inp){printf("Unable to open %c", inp); return 1;} 

        FILE *outp=fopen(obin,"wb");
        if(!outp){printf("Unable to open %c\n", obin); return 1;} 

        while(fgets(four, 4, inp) != NULL){ 

                int a;

                a = pack(four[0], four[1], four[2], four[3]);
                a = encrypt(a);

                fwrite(&a, sizeof(int), 1, outp);
        }

        printf("Encoding complete!\n");

        fclose(inp);
        fclose(outp);
}

int pack(char a, char  b, char c, char d){ 

        int p = a;

        p = (p<<CHAR_BIT) | b;
        p = (p<<CHAR_BIT) | c;
        p = (p<<CHAR_BIT) | d;

        return p;
}

int encrypt(int a){

        int obin = a>>KEY;

        return obin;
}        

代码编译但不向二进制文件写入任何内容。我们将不胜感激任何反馈、提示或提示。

提前致谢!

*编辑:

#include <stdio.h>
#include <limits.h>
#include "encoding.h"

#define KEY 3

unsigned int encrypt(int a); 
unsigned int pack(char a, char b, char d, char c);

void encoding(char itxt[], char obin[]){ 

        char four[4];

        FILE *inp=fopen(itxt,"r");
        if(!inp){printf("Unable to open %c", inp); return 1;} 

        FILE *outp=fopen(obin,"wb");
        if(!outp){printf("Unable to open %c\n", obin); return 1;} 

        while(fread(&four, sizeof(char), 4, inp) != NULL){ 

                unsigned int a;

                a = pack(four[0], four[1], four[2], four[3]);
                a = encrypt(a);

                fwrite(&a, sizeof(unsigned int), 1, outp);
        }

        printf("Encoding complete!\n");

        fclose(inp);
        fclose(outp);
}

unsigned int pack(char a, char  b, char c, char d){ 

        int p = a;

        p = (p<<CHAR_BIT) | b;
        p = (p<<CHAR_BIT) | c;
        p = (p<<CHAR_BIT) | d;

        return p;
}

 unsigned int encrypt(int a){

        int obin = (a>>KEY) | (a<<(CHAR_BIT*sizeof(a)-KEY)); 

        return obin;
}

编辑后的代码非常接近于运行。这是一个似乎有效的稍微修改的版本。困难在于没有解码功能来检查加密是否可解密。

编码代码enc37.c

#include <stdio.h>
#include <limits.h>

#define KEY 3

unsigned int encrypt(unsigned int a);
unsigned int pack(unsigned char a, unsigned char b, unsigned char d, unsigned char c);
void encoding(const char itxt[], const char obin[]);

void encoding(const char itxt[], const char obin[])
{
    char four[4];

    FILE *inp = fopen(itxt, "r");
    if (!inp)
    {
        fprintf(stderr, "Unable to open %s\n", itxt);
        return;
    }

    FILE *outp = fopen(obin, "wb");
    if (!outp)
    {
        fclose(inp);
        fprintf(stderr, "Unable to open %s\n", obin);
        return;
    }

    while (fread(&four, sizeof(char), 4, inp) == 4)
    {
        unsigned int a;

        a = pack(four[0], four[1], four[2], four[3]);
        a = encrypt(a);

        fwrite(&a, sizeof(unsigned int), 1, outp);
    }

    printf("Encoding complete!\n");

    fclose(inp);
    fclose(outp);
}

unsigned int pack(unsigned char a, unsigned char b, unsigned char c, unsigned char d)
{
    unsigned int p = a;

    p = (p << CHAR_BIT) | b;
    p = (p << CHAR_BIT) | c;
    p = (p << CHAR_BIT) | d;

    return p;
}

unsigned int encrypt(unsigned int a)
{
    unsigned int obin = (a >> KEY) | (a << (CHAR_BIT * sizeof(a) - KEY));

    return obin;
}

int main(int argc, char **argv)
{
    char *i_file = "/dev/stdin";
    char *o_file = "/dev/stdout";

    if (argc == 3)
    {
        i_file = argv[1];
        o_file = argv[2];
    }

    encoding(i_file, o_file);
    return 0;
}

参数列表处理允许您在命令行上指定输入和输出的文件名,但它默认为从标准输入读取和写入标准输出。

解码码dec37.c

#include <stdio.h>
#include <limits.h>

#define KEY 3

typedef unsigned char Byte;
typedef unsigned int  Uint;

Uint decrypt(Uint a);
Uint pack(Byte a, Byte b, Byte d, Byte c);
void unpack(Uint value, Byte *data);
void decoding(const char ibin[], const char otxt[]);

void decoding(const char ibin[], const char otxt[])
{
    FILE *inp = fopen(ibin, "rb");
    if (!inp)
    {
        fprintf(stderr, "Unable to open %s\n", ibin);
        return;
    }

    FILE *outp = fopen(otxt, "w");
    if (!outp)
    {
        fclose(inp);
        fprintf(stderr, "Unable to open %s\n", otxt);
        return;
    }

    Uint value;
    while (fread(&value, sizeof(value), 1, inp) == 1)
    {
        Byte four[4];
        value = decrypt(value);
        unpack(value, four);
        fwrite(four, sizeof(four), 1, outp);
    }

    printf("Decoding complete!\n");

    fclose(inp);
    fclose(outp);
}

void unpack(Uint value, Byte *data)
{
    data[0] = (value >> (3 * CHAR_BIT)) & 0xFF;
    data[1] = (value >> (2 * CHAR_BIT)) & 0xFF;
    data[2] = (value >> (1 * CHAR_BIT)) & 0xFF;
    data[3] = (value >> (0 * CHAR_BIT)) & 0xFF;
}

Uint decrypt(Uint a)
{
    Uint obin = (a << KEY) | (a >> (CHAR_BIT * sizeof(a) - KEY));

    return obin;
}

int main(int argc, char **argv)
{
    char *i_file = "/dev/stdin";
    char *o_file = "/dev/stdout";

    if (argc == 3)
    {
        i_file = argv[1];
        o_file = argv[2];
    }

    decoding(i_file, o_file);
    return 0;
}

测试

如果加密程序是enc37,解密程序是dec37,那么你可以运行这样的命令:

$ ./enc37 enc37.txt enc37.bin
$ ./dec37 enc37.bin dec37.txt
$ diff enc37.txt dec37.txt
$

只要输入文件 (enc37.txt) 的长度是 4 字节的倍数。我在不同时间使用 enc37.cdec37.c 作为输入文件。

你也可以逆序使用解密和加密程序,仍然可以得到往返转换。

您不应该将可能带符号的负整数向右移动;所有这些 char 都应该翻译成 unsigned long,而不是 intint 不仅可以存储 negative 数字(我确定你不想要,但这也会导致基于底层整数表示的细微不同的行为)。还有 t运行cation; int 不能便携存储四个 8 位八位字节,而 unsigned long 可以。

CHAR_BIT*sizeof(a)-KEY 似乎除了标牌问题之外还可能违反填充,而不是说您可能 运行 陷入这些问题。尽管如此,它们应该被修复以避免浪费时间调试看起来晦涩难懂且可能难以修补的问题。

您可以将 unsigned long 拆分为您想要的两个部分(我们称它们为 headtail),前提是您为 headtail 来自 ULONG_MAX.

unsigned long head_mask = ULONG_MAX >> key,
              tail_mask = ~head_mask;

... 或

unsigned long head_mask = ULONG_MAX << key,
              tail_mask = ~head_mask;

... 等等。这些将产生按位相反的掩码,然后您可以使用 & 操作(如您所愿)来提取您的两组字符。 head_mask 需要向右移动 key 以使其对齐,但至少这将保证您定义明确。