我正在开发一个程序,它使用read(),write(),open()和close()来处理文件。我们给出了一个二进制文件来排序。
我的困惑从阅读步骤开始。根据我的理解,read将文件内容放入字符数组中。因此,如果我不完全关闭,则意味着每个索引都包含一个字节的信息。记录分别用空格分隔。我按照每个包含的前四个字节对它们进行排序。
我知道记录的格式,但数据具有可变范围。幸运的是,记录之间只有空格,没有一个空格。该结构是一个整数作为文件头,表示有多少记录。每个密钥是4个字节,后跟4个字节,表示有多少数据,然后是没有空格的数据。数据的大小不包括空格。
C库中的排序例程是否可以处理为字符而不是整数?此外,我不知道从哪里开始分离和重新安排记录。我是否必须将每个提取到一个记录结构数组并从那里排序?
我是C新手,使用这些特定功能无法在线找到。这是从家庭作业,但到期日已过;我只是想让我的理解加快速度。
答案 0 :(得分:0)
如果文件是二进制的,当你写的时候 - 那么记录没有被任何东西分开,你只需要知道每条记录的大小(所有记录可能都有相同的大小)。
对于排序,您可以使用标准库函数,例如qsort。此函数使用您提供的回调,因此它可以处理任何类型的数据。在qsort返回后,您将重新排列数据。
我是否必须将每个提取到一个记录结构数组并从那里排序?
是的,对于少量记录(如在学生作业中),这是一个不错的选择。
答案 1 :(得分:0)
我们没有任何样本数据,所以我们必须创建一些。我们使用纯文本行作为数据'部分,我们可以生成0..999范围内的随机密钥,并报告行的长度作为数据的长度,并在每条记录的末尾包括空白区。
例如,此代码执行生成作业,从标准输入读取并写入标准输出:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main(void)
{
srand(time(0));
int fd = STDOUT_FILENO;
char *buffer = 0;
size_t buflen = 0;
int len;
while ((len = getline(&buffer, &buflen, stdin)) != -1)
{
int key = rand() % 1000;
write(fd, &key, sizeof(key));
write(fd, &len, sizeof(len));
write(fd, buffer, len);
write(fd, " ", 1);
}
free(buffer);
return 0;
}
考虑到输入文件(搜索&#39;伟大的panjandrum&#39;以找出文本的来源 - 它并不意味着非常明智):
So she went into the garden
to cut a cabbage-leaf
to make an apple-pie
and at the same time
a great she-bear coming down the street
pops its head into the shop
What no soap
So he died
and she very imprudently married the Barber
and there were present
the Picninnies
and the Joblillies
and the Garyulies
and the great Panjandrum himself
with the little round button at top
and they all fell to playing the game of catch-as-catch-can
till the gunpowder ran out at the heels of their boots
输出可能是:
0x0000: C3 03 00 00 1C 00 00 00 53 6F 20 73 68 65 20 77 ........So she w
0x0010: 65 6E 74 20 69 6E 74 6F 20 74 68 65 20 67 61 72 ent into the gar
0x0020: 64 65 6E 0A 20 C7 01 00 00 16 00 00 00 74 6F 20 den. ........to
0x0030: 63 75 74 20 61 20 63 61 62 62 61 67 65 2D 6C 65 cut a cabbage-le
0x0040: 61 66 0A 20 6C 03 00 00 15 00 00 00 74 6F 20 6D af. l.......to m
0x0050: 61 6B 65 20 61 6E 20 61 70 70 6C 65 2D 70 69 65 ake an apple-pie
0x0060: 0A 20 6F 02 00 00 15 00 00 00 61 6E 64 20 61 74 . o.......and at
0x0070: 20 74 68 65 20 73 61 6D 65 20 74 69 6D 65 0A 20 the same time.
0x0080: 80 02 00 00 28 00 00 00 61 20 67 72 65 61 74 20 ....(...a great
0x0090: 73 68 65 2D 62 65 61 72 20 63 6F 6D 69 6E 67 20 she-bear coming
0x00A0: 64 6F 77 6E 20 74 68 65 20 73 74 72 65 65 74 0A down the street.
0x00B0: 20 F5 02 00 00 1C 00 00 00 70 6F 70 73 20 69 74 ........pops it
0x00C0: 73 20 68 65 61 64 20 69 6E 74 6F 20 74 68 65 20 s head into the
0x00D0: 73 68 6F 70 0A 20 10 01 00 00 0D 00 00 00 57 68 shop. ........Wh
0x00E0: 61 74 20 6E 6F 20 73 6F 61 70 0A 20 4F 02 00 00 at no soap. O...
0x00F0: 0B 00 00 00 53 6F 20 68 65 20 64 69 65 64 0A 20 ....So he died.
0x0100: 73 01 00 00 2C 00 00 00 61 6E 64 20 73 68 65 20 s...,...and she
0x0110: 76 65 72 79 20 69 6D 70 72 75 64 65 6E 74 6C 79 very imprudently
0x0120: 20 6D 61 72 72 69 65 64 20 74 68 65 20 42 61 72 married the Bar
0x0130: 62 65 72 0A 20 60 01 00 00 17 00 00 00 61 6E 64 ber. `.......and
0x0140: 20 74 68 65 72 65 20 77 65 72 65 20 70 72 65 73 there were pres
0x0150: 65 6E 74 0A 20 0D 00 00 00 0F 00 00 00 74 68 65 ent. ........the
0x0160: 20 50 69 63 6E 69 6E 6E 69 65 73 0A 20 46 02 00 Picninnies. F..
0x0170: 00 13 00 00 00 61 6E 64 20 74 68 65 20 4A 6F 62 .....and the Job
0x0180: 6C 69 6C 6C 69 65 73 0A 20 88 02 00 00 12 00 00 lillies. .......
0x0190: 00 61 6E 64 20 74 68 65 20 47 61 72 79 75 6C 69 .and the Garyuli
0x01A0: 65 73 0A 20 92 00 00 00 21 00 00 00 61 6E 64 20 es. ....!...and
0x01B0: 74 68 65 20 67 72 65 61 74 20 50 61 6E 6A 61 6E the great Panjan
0x01C0: 64 72 75 6D 20 68 69 6D 73 65 6C 66 0A 20 A8 01 drum himself. ..
0x01D0: 00 00 24 00 00 00 77 69 74 68 20 74 68 65 20 6C ..$...with the l
0x01E0: 69 74 74 6C 65 20 72 6F 75 6E 64 20 62 75 74 74 ittle round butt
0x01F0: 6F 6E 20 61 74 20 74 6F 70 0A 20 15 01 00 00 3C on at top. ....<
0x0200: 00 00 00 61 6E 64 20 74 68 65 79 20 61 6C 6C 20 ...and they all
0x0210: 66 65 6C 6C 20 74 6F 20 70 6C 61 79 69 6E 67 20 fell to playing
0x0220: 74 68 65 20 67 61 6D 65 20 6F 66 20 63 61 74 63 the game of catc
0x0230: 68 2D 61 73 2D 63 61 74 63 68 2D 63 61 6E 0A 20 h-as-catch-can.
0x0240: B1 03 00 00 37 00 00 00 74 69 6C 6C 20 74 68 65 ....7...till the
0x0250: 20 67 75 6E 70 6F 77 64 65 72 20 72 61 6E 20 6F gunpowder ran o
0x0260: 75 74 20 61 74 20 74 68 65 20 68 65 65 6C 73 20 ut at the heels
0x0270: 6F 66 20 74 68 65 69 72 20 62 6F 6F 74 73 0A 20 of their boots.
0x0280:
现在,我们拥有可由程序处理的数据,以便读取,打印,排序和打印数据。
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct record
{
int key;
int data_len;
char data[];
};
static int comparator(const void *v1, const void *v2);
static void print_records(const char *tag, int num_recs, struct record **recs);
static void err_syserr(const char *msg, ...);
static void err_setarg0(const char *argv0);
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s file\n", argv[0]);
return 1;
}
err_setarg0(argv[0]);
int fd = open(argv[1], O_RDONLY);
if (fd < 0)
err_syserr("Failed to open file '%s' for reading\n", argv[1]);
struct record **records = 0;
int num_recs = 0;
int max_recs = 0;
int key;
int len;
while (read(fd, &key, sizeof(key)) == sizeof(key) &&
read(fd, &len, sizeof(len)) == sizeof(len))
{
//printf("rec num %d (key %d, len %d)\n", num_recs, key, len);
assert(len > 0);
assert(num_recs <= max_recs);
if (num_recs == max_recs)
{
size_t new_max = 2 * max_recs + 2;
void *new_recs = realloc(records, new_max * sizeof(*records));
if (new_recs == 0)
err_syserr("Failed to realloc() %zu bytes of memory\n", new_max * sizeof(*records));
records = new_recs;
max_recs = new_max;
}
int rec_size = sizeof(struct record) + len;
records[num_recs] = malloc(rec_size);
records[num_recs]->key = key;
records[num_recs]->data_len = len;
if (read(fd, records[num_recs]->data, len) != len)
err_syserr("Short read for record number %d (key %d)\n", num_recs, key);
records[num_recs]->data[len-1] = '\0';
//printf("Data: [%s]\n", records[num_recs]->data);
char blank = 0;
if (read(fd, &blank, sizeof(blank)) != sizeof(blank))
err_syserr("Missing record terminator after record number %d (key %d)\n", num_recs, key);
if (blank != ' ')
err_syserr("Unexpected EOR code %d for record number %d (key %d)\n", blank, num_recs, key);
num_recs++;
}
close(fd);
print_records("Before", num_recs, records);
qsort(records, num_recs, sizeof(struct record *), comparator);
print_records("After", num_recs, records);
for (int i = 0; i < num_recs; i++)
free(records[i]);
free(records);
return 0;
}
static int comparator(const void *v1, const void *v2)
{
int key_1 = (*(struct record **)v1)->key;
int key_2 = (*(struct record **)v2)->key;
if (key_1 < key_2)
return -1;
else if (key_1 > key_2)
return +1;
else
return 0;
}
static void print_records(const char *tag, int num_recs, struct record **recs)
{
printf("%s (%d records):\n", tag, num_recs);
for (int i = 0; i < num_recs; i++)
{
struct record *rec = recs[i];
printf("%6d: %4d: %s\n", rec->key, rec->data_len, rec->data);
}
}
/* My standard error handling - stderr.h and stderr.c */
static const char *arg0 = "unknown";
static void err_setarg0(const char *argv0)
{
arg0 = argv0;
}
static void err_syserr(const char *fmt, ...)
{
va_list args;
int errnum = errno;
fprintf(stderr, "%s: ", arg0);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, "(%d: %s)\n", errnum, strerror(errnum));
exit(EXIT_FAILURE);
}
该代码利用了每条记录的数据以换行符结束的知识,并用空字节覆盖该换行符。这也使得演示更好。另外,请注意,您无法使用灵活的数组成员创建结构数组(因为数组的元素大小相同,而具有灵活数组成员的结构的大小不同)。因此,代码使用指向具有灵活数组成员的结构的指针数组。这会影响比较器的功能,等等。
示例运行:
Before (17 records):
963: 28: So she went into the garden
455: 22: to cut a cabbage-leaf
876: 21: to make an apple-pie
623: 21: and at the same time
640: 40: a great she-bear coming down the street
757: 28: pops its head into the shop
272: 13: What no soap
591: 11: So he died
371: 44: and she very imprudently married the Barber
352: 23: and there were present
13: 15: the Picninnies
582: 19: and the Joblillies
648: 18: and the Garyulies
146: 33: and the great Panjandrum himself
424: 36: with the little round button at top
277: 60: and they all fell to playing the game of catch-as-catch-can
945: 55: till the gunpowder ran out at the heels of their boots
After (17 records):
13: 15: the Picninnies
146: 33: and the great Panjandrum himself
272: 13: What no soap
277: 60: and they all fell to playing the game of catch-as-catch-can
352: 23: and there were present
371: 44: and she very imprudently married the Barber
424: 36: with the little round button at top
455: 22: to cut a cabbage-leaf
582: 19: and the Joblillies
591: 11: So he died
623: 21: and at the same time
640: 40: a great she-bear coming down the street
648: 18: and the Garyulies
757: 28: pops its head into the shop
876: 21: to make an apple-pie
945: 55: till the gunpowder ran out at the heels of their boots
963: 28: So she went into the garden