簡體   English   中英

如果您知道字符編碼,如何從C中的文本文件讀取,然后在控制台上顯示它?

[英]How would you read from a text file in C if you know the character coding, then display it on the console?

考慮一下Java中的以下示例:

public final class Meh
{
    private static final String HELLO = "Hello world";

    private static final Charset UTF32 = Charset.forName("UTF-32");

    public static void main(final String... args)
        throws IOException
    {
        final Path tmpfile = Files.createTempFile("test", "txt");

        try (
            final Writer writer = Files.newBufferedWriter(tmpfile, UTF32);
        ) {
            writer.write(HELLO);
        }

        final String readBackFromFile;

        try (
            final Reader reader = Files.newBufferedReader(tmpfile, UTF32);
        ) {
            readBackFromFile = CharStreams.toString(reader);
        }

        Files.delete(tmpfile);

        System.out.println(HELLO.equals(readBackFromFile));
    }
}

該程序打印true 現在,一些注意事項:

  • Java中的Charset是一個同時包裝字符編碼的類。 您可以使用CharsetDecoder將字節流解碼為字符流,或者使用CharsetEncoder將字符流編碼為字節流;
  • 這就是Java具有char vs byte
  • 但是,由於歷史原因, char只是一個16位無符號數字:這是因為Java誕生時,Unicode並未在現在稱為BMP(基本多語言平面)的范圍之外定義代碼點;也就是說,在范圍U + 0000-U + FFFF(含)。

有了所有這些,上面的代碼將執行以下操作:

  • 給定一些“文本”,在這里用String表示,它首先將該文本轉換為字節序列,然后再將其寫入文件;
  • 然后它讀回該文件:它只是一個字節序列,但隨后應用反向轉換來查找存儲在其中的“原始文本”;
  • 請注意, CharStreams.toString()不在標准JDK中; 這是番石榴的班

現在,關於C ...我的問題如下:

是的,我知道UTF-32依賴於字節序; 對於Java,默認情況下為BE。

但基本上:我將如何使用C編寫以上代碼? 假設我想用C對寫面或讀面進行編程,我該怎么做?

在C語言中,通常會使用libiconvlibunistringICU之類的庫。

如果只想處理UTF-32,則可以直接寫入和讀取包含Unicode碼點的32位整數數組,其大小順序為大端或小端。 與UTF-8或UTF-16不同,UTF-32字符串不需要任何特殊的編碼和解碼。 您可以使用任何32位整數類型。 與C11的char32_t我更喜歡C99的uint32_t 例如:

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    // Could also contain non-ASCII code points.
    static const uint32_t hello[] = {
        'H', 'e', 'l', 'l', 'o', ' ',
        'w', 'o', 'r', 'l', 'd'
    };
    static size_t num_chars = sizeof(hello) / sizeof(uint32_t);

    const char *path = "test.txt";

    FILE *outstream = fopen(path, "wb");

    // Write big endian 32-bit integers        
    for (size_t i = 0; i < num_chars; i++) {
        uint32_t code_point = hello[i];

        for (int j = 0; j < 4; j++) {
            int c = (code_point >> ((3 - j) * 8)) & 0xFF;
            fputc(c, outstream);
        }
    }

    fclose(outstream);

    FILE *instream = fopen(path, "rb");

    // Get file size.
    fseek(instream, 0, SEEK_END);
    long file_size = ftell(instream);
    rewind(instream);

    if (file_size % 4) {
        fprintf(stderr, "File contains partial UTF-32");
        exit(1);
    }
    if (file_size > SIZE_MAX) {
        fprintf(stderr, "File too large");
        exit(1);
    }

    size_t num_chars_in = file_size / sizeof(uint32_t);
    uint32_t *read_back = malloc(file_size);

    // Read big endian 32-bit integers        
    for (size_t i = 0; i < num_chars_in; i++) {
        uint32_t code_point = 0;

        for (int j = 0; j < 4; j++) {
            int c = fgetc(instream);
            code_point |= c << ((3 - j) * 8);
        }

        read_back[i] = code_point;
    }

    fclose(instream);

    bool equal = num_chars == num_chars_in
                 && memcmp(hello, read_back, file_size) == 0;
    printf("%s\n", equal ? "true" : "false");

    free(read_back);

    return 0;
}

(為簡便起見,省略了大多數錯誤檢查。)

編譯並運行該程序:

$ gcc -std=c99 -Wall so.c -o so
$ ./so
true
$ hexdump -C test.txt
00000000  00 00 00 48 00 00 00 65  00 00 00 6c 00 00 00 6c  |...H...e...l...l|
00000010  00 00 00 6f 00 00 00 20  00 00 00 77 00 00 00 6f  |...o... ...w...o|
00000020  00 00 00 72 00 00 00 6c  00 00 00 64              |...r...l...d|
0000002c

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM