写入文件时奇怪地显示西里尔符号

Cyrillic symbols shown strangеly when writing to a file

我有一个 class,它有一个包含 UTF-8 字符的字符串字段 input。我的 class 还有一个方法 toString。我想使用方法 toString 将 class 的实例保存到文件中。问题是文件中写入了奇怪的符号:

my $dest = "output.txt";

print "\nBefore saving to file\n" . $message->toString() . "\n";

open (my $fh, '>>:encoding(UTF-8)', $dest) 
    or die "Cannot open $dest : $!";

lock($fh);
print $fh $message->toString();
unlock($fh);
close $fh;       

第一次打印效果很好

Input: {"paramkey":"message","paramvalue":"здравейте"}

正在打印到控制台。问题是当我写入文件时:

Input: {"paramkey":"message","paramvalue":"здÑавейÑе"}

我为 locking/unlocking 文件使用了 flock

我想你错过了
use utf8;
在您的代码中...

此代码生成您期望的 "output.txt" 文件:

#!/usr/bin/perl
use strict;
use utf8;

my $dest = "output.txt";
my $message = "здравейте";

print "\nBefore saving to file\n" . $message . "\n";

open (my $fh, '>>:encoding(UTF-8)', $dest)
    or die "Cannot open $dest : $!";

lock($fh);
print $fh $message;
close $fh;

我没有使用 toString() 方法,因为我正在处理原生字符串,而不是真实对象,但这不会改变实质...

您的 toString 方法如何运作?根据您提供的输出,我猜想 toString 方法生成的是字节而不是字符,然后 perl 在尝试转换它时会感到困惑。

在打印之前尝试 binmode STDOUT, ':encoding(UTF-8)' 看看它是否产生与文件相同的输出 - 否则你的测试是苹果和橘子。

如果它已经是字节而不是字符,您可以在没有任何 encoding(...) 层的情况下打开您的 $dest,它会起作用。

总的来说,我发现在字节上处理字符非常痛苦,但由于它解决了更多我不必再考虑的极端情况,额外的工作变得值得,但这是额外的工作.

您的 toString 方法返回的字符串内容已经采用 UTF-8 编码。当您将它打印到您的终端时,它工作正常,因为它需要 UTF-8 数据。但是当您使用

打开输出文件时
open (my $fh, '>>:encoding(UTF-8)', $dest) or die "Cannot open $dest : $!"

您要求 Perl 应该重新编码数据为 UTF-8。这会将 UTF-8 编码数据的每个字节转换为单独的 UTF-8 序列,这根本不是您想要的。很遗憾,您没有显示 $message 所属的 class 的代码,所以我无法帮助您解决这个问题

您可以通过将 open 调用更改为仅

来解决此问题
open (my $fh, '>>', $dest) or die "Cannot open $dest : $!"

这将避免额外的编码步骤。但是您真的应该在整个 Perl 代码中使用未编码的字符:从您正在读取的文件中删除任何编码,并在写入输出文件时根据需要对输出数据进行编码。