首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在php中读取UTF-16LE编码的文件?

如何在php中读取UTF-16LE编码的文件?
EN

Stack Overflow用户
提问于 2014-12-19 00:18:05
回答 2查看 4.3K关注 0票数 2

我有用BOM进行utf-16le编码的csv文件。它们可能很大,所以我真的不喜欢在内存中读取整个文件的想法。显然,问题是,我该如何开始阅读它们?

EN

回答 2

Stack Overflow用户

发布于 2014-12-19 00:28:50

逐行阅读并使用mb_convert_encoding()

代码语言:javascript
复制
$decoded_line = mb_convert_encoding ($line, "UTF-8", "UTF-16LE");

您可以选择任何目标编码,但我假设您想要使用utf-8字符串,这是目前最常见的。

此功能需要启用mbstring扩展。

然后,您可以将解码的行传递给str_getcsv函数,该函数返回一个表示当前行的数组。

票数 4
EN

Stack Overflow用户

发布于 2014-12-19 00:47:24

这是我想出来的:

代码语言:javascript
复制
class readutf16le_filter extends php_user_filter {
    function filter($in, $out, &$consumed, $closing) {
        while ($bucket = stream_bucket_make_writeable($in)) {
            # printf("filter: %s\n", to_hex($bucket->data));
            $bucket->data = iconv('UTF-16LE', 'UTF-8',
                strlen($bucket->data) && substr($bucket->data, 0, 2) == "\xff\xfe"
                    ? substr($bucket->data, 2)
                    : $bucket->data);
            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);
        }
        return PSFS_PASS_ON;
    }
}

stream_filter_register('readutf16le', 'readutf16le_filter');

$fh = fopen('1.txt', 'r');
stream_filter_append($fh, 'readutf16le');

$s = fgets($fh);
printf("%s\n", to_hex($s));

$s = fgets($fh);
printf("%s\n", to_hex($s));

$s = fgets($fh);
var_dump($s);

1.txt

代码语言:javascript
复制
a
b

输出:

代码语言:javascript
复制
filter: ff fe 61 00 0d 00 0a 00 62 00 0d 00 0a 00
61 0d 0a
62 0d 0a
bool(false)

我仍然不喜欢的是,我看不到任何方法来检测过滤器中的文件开头。然而,这不太可能造成问题。维基百科says

物料清单的使用是可选的,如果使用,则应出现在文本流的开头。

如果BOM字符出现在数据流的中间,Unicode表示应该将其解释为“宽度为零的非换行空格”(禁止在单词字形之间换行)。在Unicode3.2中,为了支持"Word Joiner“字符,这种用法被弃用,U+2060.1这允许U+FEFF仅用作物料清单。

对于IANA注册字符集UTF-16BE和UTF-16LE,不应使用字节顺序标记,因为这些字符集的名称已经确定了字节顺序。如果在这样的文本流中遇到任何地方,U+FEFF将被解释为“零宽度无中断空格”。

也许这可以用流包装器来完成。在将过滤器附加到流之前,UPD One可能会执行fread($fh, 2);

另一个可能的问题是,理论上strlen($bucket->data)可能是一个奇数。据我所知,php使用缓冲,它不太可能遇到一个奇数大小的缓冲区(通常是2的幂)。但为了适应这样的情况:

代码语言:javascript
复制
...
while ($bucket = stream_bucket_make_writeable($in)) {
    $data = strlen($bucket->data) ? 
        substr($bucket->data, 0, floor(strlen($bucket->data) / 2) * 2) : '';
    $bucket->data = iconv('UTF-16LE', 'UTF-8',
        strlen($data) && substr($data, 0, 2) == "\xff\xfe"
            ? substr($data, 2)
            : $data);
    $consumed += strlen($data);
    stream_bucket_append($out, $bucket);
    ...

不过,我不知道如何重现这个场景。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27551099

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档