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