Dưới đây là một chức năng extend_file_and_insert()
rằng hiện công việc, nhiều hơn hoặc ít hơn.
#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;
}
(Lưu ý các dòng bổ sung thêm 2013/07/19; đó là một lỗi mà chỉ hiển thị khi kích thước bộ đệm là nhỏ hơn so với số lượng dữ liệu được sao chép lên các tập tin Nhờ malat cho trỏ. . ra lỗi mã tại thử nghiệm với BUFFERSIZE = 4
)
Đây là một số mã kiểm tra quy mô nhỏ:.
#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);
}
Nó tạo ra kết quả:
12456345
1245XxxxxxX6345
1245XxxxxxX6ZzzzzzzzzzzzzzzzzzzzzzzzZ345
1245XxxxxxX6ZzzzzzzzzzYyyyyyyyyyyyyyyYzzzzzzzzzzzzzzZ345
Cần kiểm tra trên một số tệp lớn hơn (tệp lớn hơn BUFFERSIZE, nhưng sẽ rất hợp lý khi thử nghiệm với BUFFERSIZE nhỏ hơn 64 KiB; Tôi đã sử dụng 32 byte và nó có vẻ là OK). Tôi đã chỉ đánh bóng các kết quả nhưng các mẫu được thiết kế để dễ dàng thấy rằng chúng đúng. Mã không kiểm tra bất kỳ lệnh gọi nào trong số các cuộc gọi lseek()
; đó là một rủi ro nhỏ.
@ Câu trả lời của John có vẻ như đó là cách duy nhất nhưng nó sẽ liên quan đến rất nhiều việc sao chép các tệp lớn. Vì vậy, nếu có thể, tìm kiếm một cách tiếp cận khác để tuần tự hóa dữ liệu có thể là điều tốt nhất để làm. – gcbenison
@gcbenison, có, tệp nhị phân của tôi có thể là 1GB và quá trình mở rộng sẽ được kích hoạt rất nhiều thời gian nên có thể đây là vấn đề –
Sẽ tốt nhất nếu bạn có thể tránh phải chèn dữ liệu vào giữa tệp bởi vì nó quá tốn kém để làm, gấp đôi so với các tệp có kích thước gigabyte. –