【问题标题】:Reading from a file as a hexadecimal value从文件中读取十六进制值
【发布时间】:2014-02-25 08:10:21
【问题描述】:

我有一个简单的文本文件,我想将其读取为十六进制。例如,以下文本在文本文件“315c4e”中,现在这些实际上是三个字节,我想将它们保存在单独的变量中(或数组中,这是可能的)。例如,第一个变量说 uint8_t v1,应该包含 31,也就是说这个变量应该有 00110001 值(十六进制为 31)。

我在大学里做密码学作业,我必须从包含十六进制编码密文的文本文件中读取值。

【问题讨论】:

  • 如果您的文本文件包含“315c4e”,则为 6 个 ascii 字符。您想将 ascii 转换为十六进制,然后查找例如stackoverflow.com/questions/3212848/…
  • 如果您正在读取的文件在打印时会显示十六进制数据,则将该文件作为字符数据读取并使用十六进制到二进制算法转换字符。

标签: c++ c file hex


【解决方案1】:

普通的setwsetprecision 不会将读取的输入量限制为两个字符,所以是这样的:

infile >> std::setw(2) >> setprecision(2) >> std::hex >> ch;

...只是行不通。在这种情况下,读取 2 个字符的字符串并自己进行转换可能和任何事情一样简单:

#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <ctype.h>

unsigned char hstouc(std::string const &in) {
    static const std::string v{ "0123456789ABCDEF" };

    return v.find(toupper(in[0])) * 16 + v.find(toupper(in[1]));
} 

int main() {
    std::istringstream in{ "315c4e" };

    std::vector<unsigned char> vals;

    std::string temp;

    while (in >> std::setw(2) >> temp)
        vals.push_back(hstouc(temp));

    for (unsigned v : vals)
        std::cout << v << "\t";
}

如果您的输入是机器生成的,那可能就足够了。如果它可能是手动编辑的(或任何其他可能产生错误输入的东西),您可能需要/想要在转换例程中添加一些错误检查。或者,您可能想要使用类似strtoul 的东西,它已经进行了此类检查,然后将结果转换为unsigned char

【讨论】:

    【解决方案2】:

    这个问题给了我以下功能的想法,我忍不住在这里发布。顺便说一句,有没有与atob 一样的标准函数?

    int atob(unsigned char c) {
        static char     x[256];
        int             i;
        if (x[0]==0) {
            for(i=0;i<256;i++) x[i] = -1; 
            for(i=0;i<10;i++) x[i+'0'] = i;
            for(i=0;i<6;i++) x[i+'a']= x[i+'A'] = i+10;
        }
        return(x[c]);
    }
    
    int main() {
        FILE    *ff;
        int     hex, c1, c2;
    
        ff = fopen("test.txt", "r");
        for(;;) {
            c1 = fgetc(ff);
            c2 = fgetc(ff);
            if (c2 == EOF) break;
            hex = atob(c1)*16 + atob(c2);
            printf("0x%02x ", hex);
        }
        fclose(ff);
    }
    

    【讨论】:

    • 您可以将 2 个字符复制到一个以空字符结尾的 char[3] 缓冲区中,并在上面复制 sscanf(buf,"%x",...);
    【解决方案3】:

    如果要读取由空格分隔的 3 个字节(6 个字符)的元组:

    #include <cstdint>
    #include <iomanip>
    #include <iostream>
    #include <sstream>
    #include <vector>
    
    struct ToHex
    {
        typedef std::uint8_t byte;
        typedef std::istream::traits_type traits;
        byte& value;
    
        ToHex(byte& value)
        : value(value)
        {}
    
        void read(std::istream& stream) const {
            byte b[2];
            for(unsigned i = 0; i < 2; ++i) {
                traits::char_type ch = stream.get();
                if('0' <= ch && ch <= '9') b[i] = ch - '0';
                else if('a' <= ch && ch <= 'f') b[i] = ch - 'a' + 10;
                else if('A' <= ch && ch <= 'F') b[i] = ch - 'A' + 10;
                else {
                    if(ch != traits::eof())
                        stream.putback(ch);
                    stream.setstate(std::ios_base::failbit);
                }
            }
            value = b[0] * 16 + b[1]; // Rubbish if an extraction failed
        }
    };
    
    inline ToHex to_hex(ToHex::byte& value) {
        return ToHex(value);
    }
    
    inline std::istream& operator >> (std::istream& stream, const ToHex& value) {
        value.read(stream);
        return stream;
    }
    
    int main() {
        std::istringstream input(""
            "315c4e\n"
            "010c0e\n"
            "Failure");
    
        ToHex::byte a[3];
        input >> std::ws;
        while(input && ! input.eof()) {
            for(unsigned i = 0; i < 3; ++i) {
                input >> to_hex(a[i]);
            }
            if(input) {
                for(unsigned i = 0; i < 3; ++i)
                    std::cout << std::hex << std::setw(2) << std::setfill('0') << (unsigned)a[i];
                std::cout  << '\n';
                input >> std::ws;
            }
        }
        if(input.fail()) {
            std::cerr << "Failure\n";
        }
    }
    

    【讨论】:

    • "315c4e" 只是一个例子,输入文件可能包含更多字符。
    • @KhurramShehzad 这就是我在输入中添加“010c0e”和“Failure”的原因
    猜你喜欢
    • 2015-05-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 2016-11-04
    • 2015-01-26
    • 1970-01-01
    相关资源
    最近更新 更多