【问题标题】:Copy contain of an unicode file in to the char array in c将包含的 unicode 文件复制到 c 中的 char 数组中
【发布时间】:2016-05-22 16:11:02
【问题描述】:

我写了一个 c 代码如下,复制一个文件。它确实适用于unicode 文件(例如exe、rar),我使用char 数据类型数组在其中复制文件“块”。我知道,char data-type 可以将1 字节存储为扩展ASCII 标准。

fread() 函数中,将buffer[buflen] 变量用作char 数组,因为在其中复制exe 文件(100 字节)的块,然后复制buffer[buflen] 包含在另一个文件中.一个unicode 字符块怎么可能存储在char 中?为什么这段代码适用于unicode 文件真的没有任何问题?

copyFile函数:

void copyFile(const char *src, const char *dst)
{
    const int buflen = 100;
    char buffer[buflen];
    long fileSize, curFileSize, offset = 0;
    FILE *r, *w;

    r = fopen(src, "r+b");
    w = fopen(dst, "w+b");

    fseek(r, 0, SEEK_END);
    fileSize = ftell(r);
    fseek(r, 0, SEEK_SET);

    while(fileSize - (curFileSize = ftell(r)) >= buflen)
    {
        fseek(r, offset * buflen, SEEK_SET);
        fread(&buffer, sizeof(buffer), 1, r);
        fwrite(&buffer, sizeof(buffer), 1, w);
        offset++;
    }

    if ((fileSize - curFileSize) != 0)
    {
        fseek(r, (offset - 1) + (curFileSize), SEEK_SET);
        fread(&buffer, fileSize - curFileSize, 1, r);
        fwrite(&buffer, fileSize - curFileSize, 1, w);
    }

    fclose(w);
    fclose(r);
}

entrypoint 部分:

int main()
{
    copyFile("e:/1.exe", "e:/2.exe");
    return 0;
}

freadfwrite函数中使用chardata-typestruct(包含char)的原因是什么?

感谢大家帮助我。

【问题讨论】:

    标签: c unicode fread


    【解决方案1】:

    任何文件,无论编码如何,都只是一个字节序列。 char 类型可以存储任何字节,因此您只是逐字节复制文件。 (char 在 C 和 C++ 中用作字符类型和能够容纳字节的数字类型。这可能会造成混淆,但两种用法都有效。)

    freadfwrite 是根据 char 指定的,因为它们读取和写入字节。

    【讨论】:

    • 嗯,freadfwrite 被指定为char 并不完全正确,它们对地址进行操作并返回转移的items 的数量,这恰好是仅当 itemsize1 时的字节数,这正是您想要的。
    • @DavidC.Rankin 他们访问缓冲区中的字节,该缓冲区“被重新解释为unsigned char 的数组”(en.cppreference.com/w/c/io/fread)。如果我理解正确,文件中的字节被读入被视为unsigned char 类型的连续地址,然后缓冲区被重新解释为对象。但显然它们在某些时候是字节。 (TBH 我以为他们使用了char * 参数,但当然他们已经使用void * 很长时间了。)
    • @AlanStokes 请举例说明。
    • 假设您有一个包含单个字符“€”的文件。这可能在文件中表示为字节序列 E2 82 AC。如果你一个一个地复制这些字节,你最终会得到另一个文件,它也代表“€”——即使你不知道编码是如何工作的,
    • 我明白你在说什么,我认为我们谈论的是同一枚硬币的两个不同面。您正在处理从文件中解释的字节,而我正在谈论 freadfrwrite 的功能。明白这一点,我对你的说法没有任何问题,功能的两个方面都是完全正确的。
    【解决方案2】:

    好吧,您正在阅读的文件可能会使用 utf-8 编码编码,这使得U+0000---U+007f 范围内的 utf 字符与其 ASCII 相同对应物(这允许正常阅读,即使您没有符合 UNICODE 的阅读器)。 iso-latin-? 集中的字符通常映射成两个字符序列,而像 这样的字符映射成三个或更多字符序列。 只要不修改正在读取的数据,无论存储的数据类型是二进制还是文本,或者使用的编码,副本都将完全相同比原来的(或者你将不得不查看你的代码,因为它正在更改副本,使其看起来与原来的不同)

    通常,只要您不破坏这些序列中的任何一个(这意味着它们汇集到文件中并且您将它们分别写到不同的地方 --- 在副本上),通常不会有任何问题) 这通常不会发生在文件副本中。确定 UTF-8 或 UTF-16 字符的开头相对容易,因为可以识别 UNICODE 编码中的所有字符,无论是在数据流中前进还是后退。

    对于 UTF-8,字符由第一个字符组成,该字符编码该字符上的字节数,以及 n-1 这样字符的尾部(同样,很容易检测到)第一个字符将是 0b110xxxxx0b 表示从现在开始的二进制表示中的八位字节)对于一个两字节字符,0b1110xxxx 对于一个三字节字符,依此类推,直到 0b1111110x 对于一个六字节字符)它后面的其余字符, 编码为0b10xxxxxx。如果你继续前进,一旦你设置了 MSB 的字节,你就知道你在一个多字节序列的前面,你必须在第一个 0 之前计算顶部的个数,并且你有字节数组成角色。往回走,你首先遇到一个0b10xxxxxx 字符,你必须往回走,直到你得到一个0b11xxxxxx 字符,这将是序列中的第一个字符。然后你再次使用第一个过程。

    在 UTF-16 中,过程几乎相同。 0x10000 下的字符被编码为一个 16 位数字,等于或大于等于或大于的字符使用一对 16 位数字的代理编码,它们具有以下模式:0b110110xxxxxxxxxx 用于该对的前 16 位,0b110111xxxxxxxxxx第二个。这一次,你必须将0x10000 减去 UTF 字符数,然后才能得到两个 16 位量的 xxxx... 部分中的 x,但过程类似于 utf-8 中使用的过程。

    UTF-32 编码中,所有字符都存储为 32 位数量,因此目前没有多序列编码的计划。所有字符都以 32 位数量传输。在撰写本文时,标准是 V8.0,包含 1,114,112 个代码点。

    当使用另一种 UTF 编码(例如 UTF-16)时,所有字符都被编码为 16 位数量,例如,如果您以小端架构读取它们,但您以大端架构编写它们,这可能会发生变化体系结构(您应该为字符交换每两个字节以在目标体系结构中保存它们的 UTF 值)但是同样,可以有一些技巧来解决这个问题(有一个 BOM 特殊签名,允许在数据中使用字节序检查) 因此,只要您逐字节复制文件,就不会对字符进行重新排序,并且最终图像与您之前的图像完全相同,因此不必担心 UTF。

    在可变长度编码(utf-5utf-7、utf-8 和 utf-16)中,如果您破坏映射到实际 UTF 代码的多个序列之一,就会出现问题,因为这会使字符非可被解码过程识别(它变成非法字符),然后您通常会在输出中得到一些特殊字符,表示检测到无效字符。在恒定长度编码 (utf-32) 中,只有在非 32 位边界的倍数处拆分文件时,才会得到损坏的字符。

    UTF 的设计目的是成为一种有效的方式来存储和发送一组实际上未绑定的字符,为了实现这一点,它将最常见的字符映射(或尝试映射)为一个字节,将长度增加为选择了更具体或稀有的字符。

    有关 UNICODE 的主要信息来源是 UNICODE FORUM,您可以在其中找到完整 UNICODE 范围的规范、指南甚至字符映射。此处描述了 UTF-8、UTF-16 和 UTF-32 编码。对于utf-5utf-7,您必须按照上述链接进行操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-15
      • 2015-08-26
      相关资源
      最近更新 更多