fopen 一切皆有可能 - 这可能吗?

Posted

技术标签:

【中文标题】fopen 一切皆有可能 - 这可能吗?【英文标题】:fopen for everything - is this possible? 【发布时间】:2011-10-12 20:40:28 【问题描述】:

我曾经对 windows 进行编程,但我想尝试制作一个跨平台的应用程序。如果您不介意,我还有一些问题:

问题 1

有没有办法打开 UNICODE\ASCII 文件并使用裸 ANSI C 自动检测它的编码。MSDN 说 fopen() 可以在各种 UNICODE 格式(utf-8、utf-16、UNICODE BI\LI)之间切换,如果我将使用“ccs=UNICODE”标志。实验发现从 UNICODE 切换到 ASCII 不会发生,但在尝试解决这个问题时,我发现文本 Unicode 文件有一些前缀,如 0xFFFE、0xFEFF 或 0xFEBB。

FILE *file;

 __int16 isUni;
 file = _tfopen(filename, _T("rb"));
 fread(&(isUni),1,2,file);
 fclose(file);
 if( isUni == (__int16)0xFFFE || isUni == (__int16)0xFEFF || isUni == (__int16)0xFEBB)
  file = _tfopen(filename, _T("r,ccs=UNICODE"));
 else
  file = _tfopen(filename, _T("r"));         

那么,我可以做出这样的跨平台而不是那么难看的东西吗?

问题 2

我可以在 Windows 中执行类似的操作,但它可以在 Linux 中使用吗?

file = fopen(filename, "r");
fwscanf(file,"%lf",buffer);

如果没有,那么是否有某种 ANSI C 函数可以将 ASCII 字符串转换为 Unicode?我想在我的程序中使用 Unicode 字符串。

问题 3

此外,我需要将 Unicode 字符串输出到控制台。 windows里有setlocale(*),但是linux下怎么办呢?那里的控制台似乎已经是 Unicode 了。

问题 4

一般来说,我想在我的程序中使用 Unicode,但我遇到了一些奇怪的问题:

f = fopen("inc.txt","rt");
fwprintf(f,L"Текст");            // converted successfully
fclose(f);
f = fopen("inc_u8.txt","rt, ccs = UNICODE");
fprintf(f,"text");               // failed to convert
fclose(f);

附:是否有一些关于跨平台编程的好书,比较 windows 和 linux 程序代码的东西?还有一些关于使用Unicode的方法的书,实用的方法,就是这样。我不想沉浸在简单的 UNICODE BI\LI 历史中,我对特定的 C/C++ 库感兴趣。

【问题讨论】:

在这里很好地讨论了 unicode 检测的问题:blogs.msdn.com/b/oldnewthing/archive/2007/04/17/2158334.aspx 我认为 ccs=anything 不是标准的,所以它不会是可移植的 ANSI C 不支持 UNICODE,它支持 wchar_t 但 wchar_t 不是 UNICODE,因此 -> 没办法 以字节 FE 和 FF 开头的文件可能是大端 UTF-16。如果它以 FF、FE 开头,那么它可能是小结尾的 UTF-16。这两个字节是一个 16 位的 BOM(字节顺序标记),用于区分大端和小端(它们实际上是编码的“零宽度无间隔”字符)。 一些 UTF-8 文件也以编码的 BOM(将是 3 个字节)开头,但大多数不是。在没有 BOM 或某些字节超过 127 的情况下,ASCII 文件和等效的 UTF-8 文件之间实际上没有区别。 Unicode 还不是 c 标准的一部分。它可能会与 C1X 一起添加,但我们拭目以待。在那之前,看看libicu。 【参考方案1】:

问题一:

是的,您可以检测字节顺序标记,即您发现的字节序列 - 如果您的文件有一个。 在 Google 和 *** 上搜索将完成剩下的工作。 至于“不那么丑”:您可以重构/美化您的代码,例如编写一个确定BOM的函数,并在开始时执行,然后根据需要调用fopen或_tfopen。 然后你可以再次重构它,并编写你自己的 fopen 函数。但它仍然会很丑。

问题 2:

是的,但 unicode 函数在 Linux 上的调用方式与在 Windows 上的调用方式不同。 使用定义。 也许写你自己的 TCHAR.H

问题 3:

#include <locale.h>
setlocale(LC_ALL, "en.UTF-8")

man 3 设置语言环境

问题 4: 只需使用 fwprintf。 另一个不是标准。

您可以使用 wxWidgets 工具包。 它使用 unicode,并使用在 Windows、Linux、Unix 和 Mac 上具有相同实现的类。

对您来说更好的问题是如何将 ASCII 转换为 Unicode,反之亦然。 是这样的:

std::string Unicode2ASCII( std::wstring wstrStringToConvert )

    size_t sze_StringLength = wstrStringToConvert.length()  ;

    if(0 == sze_StringLength)
        return "" ;

    char* chrarry_Buffer = new char[ sze_StringLength + 1 ] ;
    wcstombs( chrarry_Buffer, wstrStringToConvert.c_str(), sze_StringLength ) ; // Unicode2ASCII, const wchar_t* C-String 2 mulibyte C-String
    chrarry_Buffer[sze_StringLength] = '\0'     ;
    std::string strASCIIstring = chrarry_Buffer ;
    delete chrarry_Buffer ;

    return strASCIIstring ;



std::wstring ASCII2Unicode( std::string strStringToConvert )

    size_t sze_StringLength = strStringToConvert.length() ;

    if(0 == sze_StringLength)
        return L"" ;

    wchar_t* wchrarry_Buffer = new wchar_t[ sze_StringLength + 1 ] ;
    mbstowcs( wchrarry_Buffer, strStringToConvert.c_str(), sze_StringLength ) ; // Unicode2ASCII, const. mulibyte C-String 2 wchar_t* C-String
    wchrarry_Buffer[sze_StringLength] = L'\0'    ;
    std::wstring wstrUnicodeString = wchrarry_Buffer ;
    delete wchrarry_Buffer   ;

    return wstrUnicodeString ;

编辑: 这里对 Linux (wchar.h) 上可用的 Unicode 函数有一些了解:

__BEGIN_NAMESPACE_STD
/* Copy SRC to DEST.  */
extern wchar_t *wcscpy (wchar_t *__restrict __dest,
            __const wchar_t *__restrict __src) __THROW;
/* Copy no more than N wide-characters of SRC to DEST.  */
extern wchar_t *wcsncpy (wchar_t *__restrict __dest,
             __const wchar_t *__restrict __src, size_t __n)
     __THROW;

/* Append SRC onto DEST.  */
extern wchar_t *wcscat (wchar_t *__restrict __dest,
            __const wchar_t *__restrict __src) __THROW;
/* Append no more than N wide-characters of SRC onto DEST.  */
extern wchar_t *wcsncat (wchar_t *__restrict __dest,
             __const wchar_t *__restrict __src, size_t __n)
     __THROW;

/* Compare S1 and S2.  */
extern int wcscmp (__const wchar_t *__s1, __const wchar_t *__s2)
     __THROW __attribute_pure__;
/* Compare N wide-characters of S1 and S2.  */
extern int wcsncmp (__const wchar_t *__s1, __const wchar_t *__s2, size_t __n)
     __THROW __attribute_pure__;
__END_NAMESPACE_STD

#ifdef __USE_XOPEN2K8
/* Compare S1 and S2, ignoring case.  */
extern int wcscasecmp (__const wchar_t *__s1, __const wchar_t *__s2) __THROW;

/* Compare no more than N chars of S1 and S2, ignoring case.  */
extern int wcsncasecmp (__const wchar_t *__s1, __const wchar_t *__s2,
            size_t __n) __THROW;

/* Similar to the two functions above but take the information from
   the provided locale and not the global locale.  */
# include <xlocale.h>

extern int wcscasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
             __locale_t __loc) __THROW;

extern int wcsncasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
              size_t __n, __locale_t __loc) __THROW;
#endif


/* Special versions of the functions above which take the locale to
   use as an additional parameter.  */
extern long int wcstol_l (__const wchar_t *__restrict __nptr,
              wchar_t **__restrict __endptr, int __base,
              __locale_t __loc) __THROW;

extern unsigned long int wcstoul_l (__const wchar_t *__restrict __nptr,
                    wchar_t **__restrict __endptr,
                    int __base, __locale_t __loc) __THROW;

__extension__
extern long long int wcstoll_l (__const wchar_t *__restrict __nptr,
                wchar_t **__restrict __endptr,
                int __base, __locale_t __loc) __THROW;

__extension__
extern unsigned long long int wcstoull_l (__const wchar_t *__restrict __nptr,
                      wchar_t **__restrict __endptr,
                      int __base, __locale_t __loc)
     __THROW;

extern double wcstod_l (__const wchar_t *__restrict __nptr,
            wchar_t **__restrict __endptr, __locale_t __loc)
     __THROW;

extern float wcstof_l (__const wchar_t *__restrict __nptr,
               wchar_t **__restrict __endptr, __locale_t __loc)
     __THROW;

extern long double wcstold_l (__const wchar_t *__restrict __nptr,
                  wchar_t **__restrict __endptr,
                  __locale_t __loc) __THROW;


/* Copy SRC to DEST, returning the address of the terminating L'\0' in
   DEST.  */
extern wchar_t *wcpcpy (wchar_t *__restrict __dest,
            __const wchar_t *__restrict __src) __THROW;

/* Copy no more than N characters of SRC to DEST, returning the address of
   the last character written into DEST.  */
extern wchar_t *wcpncpy (wchar_t *__restrict __dest,
             __const wchar_t *__restrict __src, size_t __n)
     __THROW;
#endif  /* use GNU */


/* Wide character I/O functions.  */

#ifdef  __USE_XOPEN2K8
/* Like OPEN_MEMSTREAM, but the stream is wide oriented and produces
   a wide character string.  */
extern __FILE *open_wmemstream (wchar_t **__bufloc, size_t *__sizeloc) __THROW;
#endif

#if defined __USE_ISOC95 || defined __USE_UNIX98
__BEGIN_NAMESPACE_STD

/* Select orientation for stream.  */
extern int fwide (__FILE *__fp, int __mode) __THROW;


/* Write formatted output to STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int fwprintf (__FILE *__restrict __stream,
             __const wchar_t *__restrict __format, ...)
     /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
/* Write formatted output to stdout.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int wprintf (__const wchar_t *__restrict __format, ...)
     /* __attribute__ ((__format__ (__wprintf__, 1, 2))) */;
/* Write formatted output of at most N characters to S.  */
extern int swprintf (wchar_t *__restrict __s, size_t __n,
             __const wchar_t *__restrict __format, ...)
     __THROW /* __attribute__ ((__format__ (__wprintf__, 3, 4))) */;

/* Write formatted output to S from argument list ARG.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int vfwprintf (__FILE *__restrict __s,
              __const wchar_t *__restrict __format,
              __gnuc_va_list __arg)
     /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
/* Write formatted output to stdout from argument list ARG.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int vwprintf (__const wchar_t *__restrict __format,
             __gnuc_va_list __arg)
     /* __attribute__ ((__format__ (__wprintf__, 1, 0))) */;
/* Write formatted output of at most N character to S from argument
   list ARG.  */
extern int vswprintf (wchar_t *__restrict __s, size_t __n,
              __const wchar_t *__restrict __format,
              __gnuc_va_list __arg)
     __THROW /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */;


/* Read formatted input from STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int fwscanf (__FILE *__restrict __stream,
            __const wchar_t *__restrict __format, ...)
     /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
/* Read formatted input from stdin.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int wscanf (__const wchar_t *__restrict __format, ...)
     /* __attribute__ ((__format__ (__wscanf__, 1, 2))) */;
/* Read formatted input from S.  */
extern int swscanf (__const wchar_t *__restrict __s,
            __const wchar_t *__restrict __format, ...)
     __THROW /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;

# if defined __USE_ISOC99 && !defined __USE_GNU \
     && (!defined __LDBL_COMPAT || !defined __REDIRECT) \
     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
#  ifdef __REDIRECT
/* For strict ISO C99 or POSIX compliance disallow %as, %aS and %a[
   GNU extension which conflicts with valid %a followed by letter
   s, S or [.  */
extern int __REDIRECT (fwscanf, (__FILE *__restrict __stream,
                 __const wchar_t *__restrict __format, ...),
               __isoc99_fwscanf)
     /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
extern int __REDIRECT (wscanf, (__const wchar_t *__restrict __format, ...),
               __isoc99_wscanf)
     /* __attribute__ ((__format__ (__wscanf__, 1, 2))) */;
extern int __REDIRECT_NTH (swscanf, (__const wchar_t *__restrict __s,
                     __const wchar_t *__restrict __format,
                     ...), __isoc99_swscanf)
     /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
#  else
extern int __isoc99_fwscanf (__FILE *__restrict __stream,
                 __const wchar_t *__restrict __format, ...);
extern int __isoc99_wscanf (__const wchar_t *__restrict __format, ...);
extern int __isoc99_swscanf (__const wchar_t *__restrict __s,
                 __const wchar_t *__restrict __format, ...)

【讨论】:

对,但是思路是一样的。使用的函数是普通的 C 函数。只需使用 malloc 代替 new,wcslen 代替 wstring.length,将 string 更改为 char* 并将 wstring 更改为 wchar_t*,然后在任何地方都省略 .c_str(),然后您就有了纯 C 代码。【参考方案2】:

正如我在评论中所建议的,您应该查看ICU,它是 IBM 创建的用于 Unicode 处理的跨平台 C 库。它通过一个非常强大的 String 类为 C++ 和 Java 提供了额外的支持。它在androidios等很多地方都有使用,因此非常稳定和成熟。

【讨论】:

以上是关于fopen 一切皆有可能 - 这可能吗?的主要内容,如果未能解决你的问题,请参考以下文章

探秘千年沉船,零距离接触空前巨鲸,VR让一切皆有可能

2021.10.16我的第一篇博客:一切皆有可能!

一切皆有可能——Golang中的“ThreadLocal”库

看懂Python爬虫框架,所见即所得一切皆有可能

动画剪辑:rect 属性?

python--15 字典:当索引不好用