Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 检测';文本';文件类型(ANSI与UTF-8)_Delphi_Utf 8_Delphi 7 - Fatal编程技术网

Delphi 检测';文本';文件类型(ANSI与UTF-8)

Delphi 检测';文本';文件类型(ANSI与UTF-8),delphi,utf-8,delphi-7,Delphi,Utf 8,Delphi 7,我用Delphi(7)编写了一个应用程序(心理测试考试),它创建了一个标准文本文件——即文件类型为ANSI 有人将程序移植到Internet上运行,可能使用Java,生成的文本文件类型为UTF-8 读取这些结果文件的程序必须同时读取Delphi创建的文件和通过Internet创建的文件 虽然我可以将UTF-8文本转换为ANSI(使用巧妙命名的函数UTF8ToANSI),但如何提前知道我拥有哪种文件 鉴于我“拥有”文件格式,我认为最简单的处理方法是在文件中的已知位置放置一个标记,它将告诉我程序的来

我用Delphi(7)编写了一个应用程序(心理测试考试),它创建了一个标准文本文件——即文件类型为ANSI

有人将程序移植到Internet上运行,可能使用Java,生成的文本文件类型为UTF-8

读取这些结果文件的程序必须同时读取Delphi创建的文件和通过Internet创建的文件

虽然我可以将UTF-8文本转换为ANSI(使用巧妙命名的函数UTF8ToANSI),但如何提前知道我拥有哪种文件

鉴于我“拥有”文件格式,我认为最简单的处理方法是在文件中的已知位置放置一个标记,它将告诉我程序的来源(Delphi/Internet),但这似乎是欺骗


提前感谢。

如果UTF文件以UTF-8字节顺序标记(BOM)开头,这很容易:

function UTF8FileBOM(const FileName: string): boolean;
var
  txt: file;
  bytes: array[0..2] of byte;
  amt: integer;
begin

  FileMode := fmOpenRead;
  AssignFile(txt, FileName);
  Reset(txt, 1);

  try
    BlockRead(txt, bytes, 3, amt);
    result := (amt=3) and (bytes[0] = $EF) and (bytes[1] = $BB) and (bytes[2] = $BF);
  finally    
    CloseFile(txt);
  end;

end;

否则,它就要困难得多。

没有100%确定的方法来识别ANSI(例如Windows-1250)编码和UTF-8编码。有些ANSI文件不能是有效的UTF-8,但每个有效的UTF-8文件也可能是不同的ANSI文件。(更不用说仅ASCII数据了,这两种数据在定义上都是ANSI和UTF-8,但这纯粹是一个理论方面。)

例如,序列C4 8D可能是UTF-8中的“č”字符,也可能是windows-1250中的“ÄŤ”。两者都是可能和正确的。但是,例如,8D 9A在windows-1250中可以是“Ťš”,但它不是有效的UTF-8字符串

你必须求助于某种启发式方法,例如

  • 如果文件包含的序列不能是有效的UTF-8,则假定它是ANSI
  • 否则,如果文件以UTF-8 BOM(EF BB BF)开头,则假定它是UTF-8(但可能不是,以此类字符开头的纯文本ANSI文件是不可能的)
  • 否则,假设它是UTF-8。(或者,尝试更多的启发法,可能使用文本语言的知识,等等)

  • 另请参见。

    读取时,请尝试将文件解析为UTF-8。如果UTF-8无效,则将该文件解释为传统编码(ANSI)。这将适用于大多数文件,因为传统编码文件不太可能是有效的UTF-8

    windows称之为ANSI的是一个依赖于系统语言环境的字符集。而且这篇文章在俄文、亚文或。。。窗户


    虽然VCL在Delphi7中不支持Unicode,但您仍然应该在内部使用Unicode,并且只转换为ANSI来显示它。我将我的一个程序本地化为韩语和俄语,这是我让它顺利运行的唯一方法。您仍然只能在设置为韩语的系统上显示韩语本地化,但至少可以在任何系统上编辑文本文件。

    如果我们对其进行汇总,则:

    • 基本用法的最佳解决方案是使用过时的(如果我们使用;)
    • 高级使用的最佳解决方案是使用上述功能,然后检查BOM(~1KB),然后检查特定操作系统下的区域设置信息,只有这样才能获得大约98%的准确性
    人们可能会感兴趣的其他信息:

    函数文件maybeutf8(文件名:WideString):布尔值;
    变量
    流:TMemoryStream;
    字节读取:整数;
    ArrayBuff:字节的数组[0..127];
    PreviousByte:字节;
    i:整数;
    YesSequence,NoSequence:整数;
    开始
    如果不存在WideFileExists(文件名),则
    出口
    是序列:=0;
    鼻序列:=0;
    Stream:=TMemoryStream.Create;
    尝试
    Stream.LoadFromFile(文件名);
    重复
    {从TMemoryStream读取}
    BytesRead:=Stream.Read(ArrayBuff,High(ArrayBuff)+1);
    {处理缓冲区中的字节}
    如果BytesRead>1,则
    开始
    对于i:=1到BytesRead-1do
    开始
    前一字节:=ArrayBuff[i-1];
    如果((ArrayBuff[i]和$c0)=$80),则
    开始
    如果((上一字节和$c0)=$c0),则
    开始
    公司(YesSequences)
    结束
    其他的
    开始
    如果((上一字节和$80)=$0),则
    公司(NoSequences);
    结束;
    结束;
    结束;
    结束;
    直到(字节读取<(高(阵列缓冲)+1));
    //下面,>=使ASCII文件=UTF-8,这没有问题。
    //Simple>只能捕获UTF-8;
    结果:=(YesSequences>=NoSequences);
    最后
    免费;
    结束;
    结束;
    
    现在测试这个函数

    在我看来,正确开始执行此检查的唯一方法是首先检查OS字符集,因为最终几乎在所有情况下都会引用OS。无论如何,没有办法逃避

    备注:

    • WideFileExists()函数取自TntClasses.pas()
    //如果可以解码,则为UTF8
    函数isFileUTF8(const-Tex:AnsiString):布尔;
    开始
    结果:=(Tex'')和(utf8解码(Tex');
    结束;
    
    在UTF-8数据上查找BOM是非常罕见的,因为UTF-8是不可知端的,因此。@Andreas哦,是的。但是,这个答案仍然是-1。你真的不能指望在UTF-8数据中有一个BOM表。一个好的答案是测试数据是否有效UTF-8…@David:这个答案基本上是说“查找BOM”。(这就是所有代码所做的。)除了10次中有9次,UTF-8文件没有BOM,因为它不需要BOM…@dkarp单词ANSI,因为Microsoft表示本地遗留字符集,根据操作系统语言的不同,系统之间可能会有所不同。@Andreas我是两个反对票中的一个,我想我已经解释了原因。90%以上的时候,你的答案根本没有帮助,因为UTF-8文件很少有BOM表。这有点像回答“如何复制MySQL的
    utf8\uUnicode\uCIfunction FileMayBeUTF8(FileName: WideString): Boolean;
    var
     Stream: TMemoryStream;
     BytesRead: integer;
     ArrayBuff: array[0..127] of byte;
     PreviousByte: byte;
     i: integer;
     YesSequences, NoSequences: integer;
    
    begin
       if not WideFileExists(FileName) then
         Exit;
       YesSequences := 0;
       NoSequences := 0;
       Stream := TMemoryStream.Create;
       try
         Stream.LoadFromFile(FileName);
         repeat
    
         {read from the TMemoryStream}
    
           BytesRead := Stream.Read(ArrayBuff, High(ArrayBuff) + 1);
               {Do the work on the bytes in the buffer}
           if BytesRead > 1 then
             begin
               for i := 1 to BytesRead-1 do
                 begin
                   PreviousByte := ArrayBuff[i-1];
                   if ((ArrayBuff[i] and $c0) = $80) then
                     begin
                       if ((PreviousByte and $c0) = $c0) then
                         begin
                           inc(YesSequences)
                         end
                       else
                         begin
                           if ((PreviousByte and $80) = $0) then
                             inc(NoSequences);
                         end;
                     end;
                 end;
             end;
         until (BytesRead < (High(ArrayBuff) + 1));
    //Below, >= makes ASCII files = UTF-8, which is no problem.
    //Simple > would catch only UTF-8;
         Result := (YesSequences >= NoSequences);
    
       finally
         Stream.Free;
       end;
    end;
    
    //if is possible to decoded,then it is UTF8
    
    function isFileUTF8(const Tex : AnsiString): boolean;
    begin
      result := (Tex <> '') and (UTF8Decode(Tex) <> '');
    end;