Возможно, вам понадобится код, подобный следующему:
multi-rw.h
#ifndef JLSS_ID_MULTI_RW_H
#define JLSS_ID_MULTI_RW_H
#include <sys/types.h>
extern ssize_t multi_read(int fd, char *buffer, size_t nbytes);
extern ssize_t multi_write(int fd, const char *buffer, size_t nbytes);
#endif
multi-rw.c
Немного прискорбно, что блок тестового кода должен предшествовать активным функциям, но это необходимо (и тестовый код необходим - по крайней мере, я считаю его чрезвычайно полезным и обнадеживающим). Я предполагаю, что это могло войти в отдельный заголовочный файл (multi-rw-test.h
или около того), который был бы включен условно; было бы лучше для презентации на SO, но в противном случае это просто еще один файл, о котором нужно беспокоиться.
#include "multi-rw.h"
#include <unistd.h>
#ifdef TEST
#ifndef MAX_WRITE_SIZE
#define MAX_WRITE_SIZE 64
#endif
#ifndef MAX_READ_SIZE
#define MAX_READ_SIZE 64
#endif
static inline size_t min_size(size_t x, size_t y) { return (x < y) ? x : y; }
static inline ssize_t pseudo_read(int fd, char *buffer, size_t nbytes)
{
return read(fd, buffer, min_size(MAX_READ_SIZE, nbytes));
}
static inline ssize_t pseudo_write(int fd, const char *buffer, size_t nbytes)
{
return write(fd, buffer, min_size(MAX_READ_SIZE, nbytes));
}
#undef read
#undef write
#define read(fd, buffer, nbytes) pseudo_read(fd, buffer, nbytes)
#define write(fd, buffer, nbytes) pseudo_write(fd, buffer, nbytes)
#endif
ssize_t multi_read(int fd, char *buffer, size_t nbytes)
{
ssize_t nb = 0;
size_t nleft = nbytes;
ssize_t tbytes = 0;
while (nleft > 0 && (nb = read(fd, buffer, nleft)) > 0)
{
tbytes += nb;
buffer += nb;
nleft -= nb;
}
if (tbytes == 0)
tbytes = nb;
return tbytes;
}
ssize_t multi_write(int fd, const char *buffer, size_t nbytes)
{
ssize_t nb = 0;
size_t nleft = nbytes;
ssize_t tbytes = 0;
while (nleft > 0 && (nb = write(fd, buffer, nleft)) > 0)
{
tbytes += nb;
buffer += nb;
nleft -= nb;
}
if (tbytes == 0)
tbytes = nb;
return tbytes;
}
#ifdef TEST
#include "stderr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 0)
err_setarg0(argv[0]);
char buffer[4096];
ssize_t ibytes;
while ((ibytes = multi_read(0, buffer, sizeof(buffer))) > 0)
{
ssize_t obytes;
if ((obytes = multi_write(1, buffer, ibytes)) != ibytes)
err_syserr("failed to write %lld bytes - only wrote %lld bytes\n",
(long long)ibytes, (long long)obytes);
}
if (ibytes < 0)
err_syserr("I/O error reading standard input: ");
return 0;
}
#endif
Испытательный жгут позволяет проверять чтение кода со стандартного ввода и запись на стандартный вывод. Вы можете настроить объем данных, читаемых с помощью (например) параметров командной строки компиляции -DMAX_WRITE_SIZE=132
и -DMAX_READ_SIZE=103
. Вам необходимо протестировать его на файлах, меньших (а) 4096 байт и (б) меньших, чем максимальные размеры чтения и записи, а также на файлах, превышающих 4096 байт. Если вы достаточно мотивированы, вы можете обновить функции pseudo_read()
и pseudo_write()
, чтобы генерировать ошибки квази-случайным образом, чтобы увидеть, как код обрабатывает такие ошибки.