Вы делаете IO символ за символом. Это будет бесполезно и болезненно S-L-O-W, даже с буферизированными потоками.
Воспользуйтесь преимуществами того, что ваши данные хранятся в ваших файлах как строки с нулевым завершением.
Предполагая, что вы чередуя последовательности нулевых байты из каждого файла, и работает на платформе POSIX, так что вы можете просто mmap()
входных файлы:
typedef struct mapdata
{
const char *ptr;
size_t bytes;
} mapdata_t;
mapdata_t mapFile(const char *filename)
{
mapdata_t data;
struct stat sb;
int fd = open(filename, O_RDONLY);
fstat(fd, &sb);
data.bytes = sb.st_size;
/* assumes we have a NUL byte after the file data
If the size of the file is an exact multiple of the
page size, we won't have the terminating NUL byte! */
data.ptr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
return(data);
}
void unmapFile(mapdata_t data)
{
munmap(data.ptr, data.bytes);
}
void mergeFiles(const char *file1, const char *file2, const char *output)
{
char zeroByte = '\0';
mapdata_t data1 = mapFile(file1);
mapdata_t data2 = mapFile(file2);
size_t strOffset1 = 0UL;
size_t strOffset2 = 0UL;
/* get a page-aligned buffer - a 64kB alignment should work */
char *iobuffer = memalign(64UL * 1024UL, 1024UL * 1024UL);
/* memset the buffer to ensure the virtual mappings exist */
memset(iobuffer, 0, 1024UL * 1024UL);
/* use of direct IO should reduce memory pressure - the 1 MB
buffer is already pretty large, and since we're not seeking
the page cache is really only slowing things down */
int fd = open(output, O_RDWR | O_TRUNC | O_CREAT | O_DIRECT, 0644);
FILE *outputfile = fdopen(fd, "wb");
setvbuf(outputfile, iobuffer, _IOFBF, 1024UL * 1024UL);
/* loop until we reach the end of either mapped file */
for (;;)
{
fputs(data1.ptr + strOffset1, outputfile);
fwrite(&zeroByte, 1, 1, outputfile);
fputs(data2.ptr + strOffset2, outputfile);
fwrite(&zeroByte, 1, 1, outputfile);
/* skip over the string, assuming there's one NUL
byte in between strings */
strOffset1 += 1 + strlen(data1.ptr + strOffset1);
strOffset2 += 1 + strlen(data2.ptr + strOffset2);
/* if either offset is too big, end the loop */
if ((strOffset1 >= data1.bytes) ||
(strOffset2 >= data2.bytes))
{
break;
}
}
fclose(outputfile);
unmapFile(data1);
unmapFile(data2);
}
Я положил в отсутствии ошибки проверки на всех. Вам также нужно будет добавить соответствующие файлы заголовков.
Обратите внимание, что данные файла принимаются равным NOT, что является точным кратным размеру системной страницы, тем самым гарантируя, что после содержимого файла отображается NUL-байт. Если размер файла является точным кратным размеру страницы, вам нужно будет добавить mmap()
дополнительную страницу после содержимого файла, чтобы убедиться, что для завершения последней строки существует NUL-байт.
Или вы можете положиться на то, что в качестве последнего байта содержимого файла имеется байт NUL. Если это когда-либо окажется неверным, вы, скорее всего, получите либо SEGV, либо поврежденные данные.
Я бы сказал две вещи. FIrst, я всегда думал, что 'write' быстрее, чем' fwrite'. Во-вторых, не записывайте каждый байт в файл. Сделайте свой собственный промежуточный буфер и напишите в файл большие куски данных. – GMichael
Сделайте свой код доступным для чтения. – Inline
@GMichael спасибо за ваш совет. fwrite должен быть буферизирован. Считаете ли вы, что функция называется самокритичной? –