Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.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
在C中将整个文件转换为小写的最佳方法_C_Linux_Lowercase - Fatal编程技术网

在C中将整个文件转换为小写的最佳方法

在C中将整个文件转换为小写的最佳方法,c,linux,lowercase,C,Linux,Lowercase,我想知道是否有一个真正好的(性能)解决方案,如何将整个文件转换成小写的C。 我使用fgetc将字符转换为小写,并使用fputc将其写入另一个临时文件。最后,我删除了原始文件,并将tempfile重命名为旧的原始文件名。但我认为必须有更好的解决办法 我得说你一针见血。临时文件意味着您在确定处理完成之前不会删除原始文件,这意味着一旦出错,原始文件将保留。我认为这是正确的做法 正如另一个答案(如果文件大小允许)所建议的,您可以通过mmap函数对文件进行内存映射,并使其在内存中随时可用(如果文件小于页面

我想知道是否有一个真正好的(性能)解决方案,如何将整个文件转换成小写的C。
我使用fgetc将字符转换为小写,并使用fputc将其写入另一个临时文件。最后,我删除了原始文件,并将tempfile重命名为旧的原始文件名。但我认为必须有更好的解决办法

我得说你一针见血。临时文件意味着您在确定处理完成之前不会删除原始文件,这意味着一旦出错,原始文件将保留。我认为这是正确的做法


正如另一个答案(如果文件大小允许)所建议的,您可以通过mmap函数对文件进行内存映射,并使其在内存中随时可用(如果文件小于页面大小,则没有实际性能差异,因为一旦您进行了第一次读取,它可能会被读入内存)

通过使用
fread
fwrite
读取和写入大块输入/输出,通常可以在大输入上获得更快的速度。此外,您可能还应该将一个较大的块(如果可能的话,整个文件)转换为内存,然后一次将其全部写入


编辑:我还记得一件事。有时,如果选择素数(至少不是2的幂)作为缓冲区大小,程序可能会更快。我似乎记得这与缓存机制的细节有关。

如果你知道字符编码是什么,你肯定可以大大加快速度。因为您使用的是Linux和C,所以我将在这里冒险假设您使用的是ASCII

在ASCII码中,我们知道A-Z和A-Z是连续的,并且总是相距32。因此,我们可以忽略toLower()函数的安全检查和区域设置检查,并执行如下操作:

(伪代码) 文件中的foreach(int)char c: c-=32

或者,如果可能有大写和小写字母,请执行如下检查 if(c>64&&c<91)//大写ASCII范围 然后进行减法运算并将其写入文件

此外,批处理写入速度更快,因此我建议首先写入数组,然后一次性将数组的内容写入文件


这应该要快得多。

这并不能真正回答问题(社区wiki),但这里有一个(过度?)优化的函数,可以将文本转换为小写:

#include <assert.h>
#include <ctype.h>
#include <stdio.h>

int fast_lowercase(FILE *in, FILE *out)
{
    char buffer[65536];
    size_t readlen, wrotelen;
    char *p, *e;
    char conversion_table[256];
    int i;

    for (i = 0; i < 256; i++)
        conversion_table[i] = tolower(i);

    for (;;) {
        readlen = fread(buffer, 1, sizeof(buffer), in);
        if (readlen == 0) {
            if (ferror(in))
                return 1;
            assert(feof(in));
            return 0;
        }

        for (p = buffer, e = buffer + readlen; p < e; p++)
            *p = conversion_table[(unsigned char) *p];

        wrotelen = fwrite(buffer, 1, readlen, out);
        if (wrotelen != readlen)
            return 1;
    }
}
#包括
#包括
#包括
int快速小写(文件*输入,文件*输出)
{
字符缓冲区[65536];
尺寸(单位:mm)和尺寸(单位:mm);
字符*p,*e;
字符转换_表[256];
int i;
对于(i=0;i<256;i++)
换算表[i]=下限(i);
对于(;;){
readlen=fread(缓冲区,1,缓冲区大小,in);
如果(readlen==0){
如果(铁(in))
返回1;
断言(feof(in));
返回0;
}
for(p=buffer,e=buffer+readlen;p
当然,这并不支持Unicode

我使用GCC4.6.0和i686(32位)Linux在Intel Core 2 T5500(1.66GHz)上对此进行了基准测试。一些有趣的观察结果:

  • 使用
    malloc
    而不是在堆栈上分配
    buffer
    时,速度约为75%
  • 使用条件表比使用转换表快65%

如果您正在处理大文件(比如说,大到好几兆字节),并且此操作绝对是速度关键的,那么超越您所查询的内容可能是有意义的。特别要考虑的是,逐字符操作将比使用SIMD指令执行得更好。

也就是说,如果您要使用SSE2,您可以对
toupper_并行
like(伪代码)进行编码:

for(cur\u parallel\u word=块的开始;
cur_parallel_word<_块的end_;
cur_parallel_word+=平行_word_width){
/*
*在SSE2中,平行比较是关于“更大”或“相等”

*所以“>=”和“你为什么要在C中这样做?像这样的任务是脚本语言存在的目的。他想从那台计算机中挤出每一点性能。我同意delnan的观点,但解决你的问题-你认为你可以改进什么?我认为你不能做完全缓冲的拷贝,因为你必须修改stRAMM。您可以将它完全加载到中间的内存中,以避免对磁盘进行大量的攻击,但这是典型的内存吞吐量的折衷,这不是一个明显的改进。CASE转换是依赖于区域的。您是否关心其他语言,或者等效于<代码> TR AZ Z -Z <代码>?没有真正的原因来<代码> >调用
rename
之前,请先取消文件链接,因为
rename
将为您移动旧文件。此外,虽然
fgetc
使用缓冲I/O,为什么不直接请求大块数据并尽量减少您必须进行的调用次数?
for (cur_parallel_word = begin_of_block;
     cur_parallel_word < end_of_block;
     cur_parallel_word += parallel_word_width) {
    /*
     * in SSE2, parallel compares are either about 'greater' or 'equal'
     * so '>=' and '<=' have to be constructed. This would use 'PCMPGTB'.
     * The 'ALL' macro is supposed to replicate into all parallel bytes.
     */
    mask1 = parallel_compare_greater_than(*cur_parallel_word, ALL('A' - 1));
    mask2 = parallel_compare_greater_than(ALL('Z'), *cur_parallel_word);
    /*
     * vector op - and all bytes in two vectors, 'PAND'
     */
    mask = mask1 & mask2;
    /*
     * vector op - add a vector of bytes. Would use 'PADDB'.
     */
    new = parallel_add(cur_parallel_word, ALL('a' - 'A'));
    /*
     * vector op - zero bytes in the original vector that will be replaced
     */
    *cur_parallel_word &= !mask;           // that'd become 'PANDN'
    /*
     * vector op - extract characters from new that replace old, then or in.
     */
    *cur_parallel_word |= (new & mask);    // PAND / POR
}