gpt4 book ai didi

C 在二进制文件中间写入而不覆盖任何现有内容

转载 作者:太空宇宙 更新时间:2023-11-04 12:20:54 25 4
gpt4 key购买 nike

今天的问题是我需要在二进制文件中的起始位置写入一个数字数组。我有它应该开始的位置,我不想在那之后覆盖值,只想在文件的起始位置插入数组。例如:

12345

让我们将 456 推到位置 2:

12456345

我知道我可能必须自己实现它,但我想知道您对如何尽可能高效地实现它有何看法。

最佳答案

这里有一个函数 extend_file_and_insert() 或多或少地完成了这项工作。

#include <sys/stat.h>
#include <unistd.h>

enum { BUFFERSIZE = 64 * 1024 };

#define MIN(x, y) (((x) < (y)) ? (x) : (y))

/*
off_t is signed
ssize_t is signed
size_t is unsigned

off_t for lseek() offset and return
size_t for read()/write() length
ssize_t for read()/write() return
off_t for st_size
*/

static int extend_file_and_insert(int fd, off_t offset, char const *insert, size_t inslen)
{
char buffer[BUFFERSIZE];
struct stat sb;
int rc = -1;

if (fstat(fd, &sb) == 0)
{
if (sb.st_size > offset)
{
/* Move data after offset up by inslen bytes */
size_t bytes_to_move = sb.st_size - offset;
off_t read_end_offset = sb.st_size;
while (bytes_to_move != 0)
{
ssize_t bytes_this_time = MIN(BUFFERSIZE, bytes_to_move);
ssize_t rd_off = read_end_offset - bytes_this_time;
ssize_t wr_off = rd_off + inslen;
lseek(fd, rd_off, SEEK_SET);
if (read(fd, buffer, bytes_this_time) != bytes_this_time)
return -1;
lseek(fd, wr_off, SEEK_SET);
if (write(fd, buffer, bytes_this_time) != bytes_this_time)
return -1;
bytes_to_move -= bytes_this_time;
read_end_offset -= bytes_this_time; /* Added 2013-07-19 */
}
}
lseek(fd, offset, SEEK_SET);
write(fd, insert, inslen);
rc = 0;
}
return rc;
}

(注意 2013-07-19 添加的附加行;这是一个错误,仅在缓冲区大小小于要复制到文件中的数据量时显示。感谢 malat 指出错误。现在使用 BUFFERSIZE = 4 测试代码。)

这是一些小规模的测试代码:

#include <fcntl.h>
#include <string.h>

static const char base_data[] = "12345";
typedef struct Data
{
off_t posn;
const char *data;
} Data;
static const Data insert[] =
{
{ 2, "456" },
{ 4, "XxxxxxX" },
{ 12, "ZzzzzzzzzzzzzzzzzzzzzzzzX" },
{ 22, "YyyyyyyyyyyyyyyY" },
};
enum { NUM_INSERT = sizeof(insert) / sizeof(insert[0]) };

int main(void)
{
int fd = open("test.dat", O_RDWR | O_TRUNC | O_CREAT, 0644);
if (fd > 0)
{
ssize_t base_len = sizeof(base_data) - 1;
if (write(fd, base_data, base_len) == base_len)
{
for (int i = 0; i < NUM_INSERT; i++)
{
off_t length = strlen(insert[i].data);
if (extend_file_and_insert(fd, insert[i].posn, insert[i].data, length) != 0)
break;
lseek(fd, 0, SEEK_SET);
char buffer[BUFFERSIZE];
ssize_t nbytes;
while ((nbytes = read(fd, buffer, sizeof(buffer))) > 0)
write(1, buffer, nbytes);
write(1, "\n", 1);
}
}
close(fd);
}
return(0);
}

它产生输出:

12456345
1245XxxxxxX6345
1245XxxxxxX6ZzzzzzzzzzzzzzzzzzzzzzzzZ345
1245XxxxxxX6ZzzzzzzzzzYyyyyyyyyyyyyyyYzzzzzzzzzzzzzzZ345

它应该在一些更大的文件上进行测试(比 BUFFERSIZE 大的文件,但是使用比 64 KiB 小很多的 BUFFERSIZE 进行测试是明智的;我使用了 32 字节并且似乎没问题)。我只是目测了结果,但模式的设计是为了让人们很容易看出它们是正确的。该代码不检查任何 lseek() 调用;这是一个小风险。

关于C 在二进制文件中间写入而不覆盖任何现有内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46027603/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com